diff -r fb024d5e35fa -r 64c62431ac08 multimediacommscontroller/mmccMsrppayloadformat/src/Msrppayloadformatwrite.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/multimediacommscontroller/mmccMsrppayloadformat/src/Msrppayloadformatwrite.cpp Mon Sep 06 17:32:13 2010 +0530 @@ -0,0 +1,1052 @@ +/* +* Copyright (c) 2004-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: Provides a comfort noise generator class +* +*/ + +// INCLUDE FILES + +#include +#include +#include // charconv.lib + +#include "msrppayloadformatwrite.h" +#include "mccrtpdatasink.h" +#include "Mccrtpinterface.h" + +#include "mccmsrpformatlogs.h" +#include "mccuids.hrh" +#include "mccdef.h" +#include "mccrtpmediaclock.h" +#include "mccinternaldef.h" +#include "msrppayloadformatdefs.h" +#include "mmccinterfacedef.h" +#include "mccmsrpsink.h" + + +// ----------------------------------------------------------------------------- +// CMsrpPayloadFormatRead::CMsrpPayloadFormatRead +// C++ default constructor can NOT contain any code, that +// might leave. +// +// iIdleMode is set to ETrue, because when starting we are in IdleMode +// ----------------------------------------------------------------------------- +// +CMsrpPayloadFormatWrite::CMsrpPayloadFormatWrite(): iIdleMode(ETrue) + { + } + +// ----------------------------------------------------------------------------- +// CMsrpPayloadFormatWrite::ConstructL +// Symbian 2nd phase constructor can leave. +// ----------------------------------------------------------------------------- +// +void CMsrpPayloadFormatWrite::ConstructL ( MDataSink* aSink ) + { + + DP_MSRP_WRITE("CMsrpPayloadFormatWrite::ConstructL"); + + // Set default values + iFourCC = KMccFourCCIdMSRP ; + //iFourCC.Set( TFourCC( 'T','1','4','0' ) ); + + //we are going upstream, so our source is the datapath and + // sink is the clip. If we use RTP, which we do, + // our sink is of cource the RTPSink + iClip = aSink; + iIsRtpSink = ( KMccRtpSinkUid == aSink->DataSinkType() ); + iIsMsrpSink = (KMccMsrpSinkUid == aSink->DataSinkType() ); + + // two levels of redundancy is allways assumed, not necessarily used + // RFC4103 RECOMMENDED + iRedData = new(ELeave)CArrayFixFlat(3); + + //userBuffer, handles all data put in by user + iUserBuffer = new(ELeave)CArrayFixFlat(3); + + // init data to null + TStringElement one; + TStringElement two; + TStringElement three; + iRedData->AppendL(one); + iRedData->AppendL(two); + iRedData->AppendL(three); + + // maxsize of the packet + iBuf = HBufC8::NewL( KRedHeaderSize + KDataSize ); + iData = const_cast( iBuf->Des().Ptr() ); + + if ( iIsRtpSink ) + { + CMccRtpDataSink* tmp = static_cast( aSink ); + iRtpDataSink = static_cast( tmp ); + } + else if(iIsMsrpSink) + { + CMccMsrpSink *tmp = static_cast( aSink ); + iMsrpDataSink = static_cast( tmp ); + } + else + { + DP_MSRP_WRITE("CMsrpPayloadFormatWrite::ConstructL Leaving: No RTPSink!"); + User::Leave(KErrNotSupported); + } + + // Initialize state machine + iStateMachine = CFormatEncodeStateMachine::NewL( this ); + + //init state machine to idle state + iStateMachine->ChangeState( EEncodeIdle ); + + // Construct Timer for redundant generations. + iTimer = CSendStateMachine::NewL( this ); + + } + + +// ----------------------------------------------------------------------------- +// CMsrpPayloadFormatWrite::NewL +// Two-phased constructor. +// ----------------------------------------------------------------------------- +// +CMsrpPayloadFormatWrite* CMsrpPayloadFormatWrite::NewL ( MDataSink* aSink ) + { + + + DP_MSRP_WRITE( "CMsrpPayloadFormatWrite::NewL" ); + __ASSERT_ALWAYS( aSink, User::Leave( KErrArgument ) ); + + CMsrpPayloadFormatWrite* self = new (ELeave) CMsrpPayloadFormatWrite; + CleanupStack::PushL( self ); + self->ConstructL( aSink ); + CleanupStack::Pop( self ); + return self; + + } + +// Destructor +CMsrpPayloadFormatWrite::~CMsrpPayloadFormatWrite () + { + + if ( iStateMachine ) + { + iStateMachine->Cancel(); + delete iStateMachine; + } + + if(iTimer) + { + iTimer->Cancel(); + delete iTimer; + } + + + iRtpMediaClock = NULL; + iClip = NULL; + + delete iSourceBuffer; + delete iSinkBuffer; + delete iRedData; + delete iUserBuffer; + delete iBuf; + + } + + +// ----------------------------------------------------------------------------- +// CMsrpPayloadFormatWrite::SinkThreadLogon +// Passes the logon command to the sink clip +// ----------------------------------------------------------------------------- +// +TInt CMsrpPayloadFormatWrite::SinkThreadLogon(MAsyncEventHandler& aEventHandler) + { + DP_MSRP_WRITE("CMsrpPayloadFormatWrite::SinkThreadLogon"); + iClip->SinkThreadLogon( aEventHandler ); + return KErrNone; + } + + +// ----------------------------------------------------------------------------- +// CMsrpPayloadFormatWrite::SinkThreadLogoff +// Passes the logoff command to the sink clip +// ----------------------------------------------------------------------------- +void CMsrpPayloadFormatWrite::SinkThreadLogoff() + { + DP_MSRP_WRITE("CMsrpPayloadFormatWrite::SinkThreadLogoff"); + iClip->SinkThreadLogoff(); + } + + +// ----------------------------------------------------------------------------- +// CMsrpPayloadFormatWrite::CreateSinkBufferL +// Create a sink buffer +// ----------------------------------------------------------------------------- +// +CMMFBuffer* CMsrpPayloadFormatWrite::CreateSinkBufferL( TMediaId /*aMediaId*/, + TBool &aReference ) + { + + DP_MSRP_WRITE( "CMsrpPayloadFormatWrite::CreateSinkBufferL" ); + + /* TODO: Remove me when platform supports + if ( KUidMediaTypeText != aMediaId.iMediaType ) + { + User::Leave( KErrNotSupported ); + } + */ + aReference = ETrue; + return CreateSinkBufferOfSizeL( KMaxRTTChunkSize + KRedHeaderSize ); + + } + +// ----------------------------------------------------------------------------- +// CMsrpPayloadFormatWrite::CreateSinkBufferOfSizeL +// Create a sink buffer of the given size. +// ----------------------------------------------------------------------------- +// +CMMFDataBuffer* CMsrpPayloadFormatWrite::CreateSinkBufferOfSizeL( TUint aSize ) + { + + DP_MSRP_WRITE( "CMsrpPayloadFormatWrite::CreateSinkBufferOfSizeL" ); + + if ( !iSourceBuffer ) + { + iSourceBuffer = CMMFDataBuffer::NewL( aSize ); + iSourceBuffer->Data().FillZ( aSize ); + iSourceBuffer->SetRequestSizeL( aSize ); + } + + return iSourceBuffer; + + } + +// ----------------------------------------------------------------------------- +// CMsrpPayloadFormatWrite::EmptyBufferL +// Empty the given source buffer +// ----------------------------------------------------------------------------- +// +void CMsrpPayloadFormatWrite::EmptyBufferL( CMMFBuffer* aBuffer, + MDataSource* aSupplier, + TMediaId /*aMediaId*/ ) + { + + DP_MSRP_WRITE("CMsrpPayloadFormatWrite::EmptyBufferL"); + + __ASSERT_ALWAYS( aBuffer, User::Leave( KErrArgument ) ); + __ASSERT_ALWAYS ( aBuffer == iSourceBuffer, User::Leave( KErrArgument ) ); + __ASSERT_ALWAYS( aSupplier, User::Leave( KErrArgument ) ); + + // TODO: Remove me when platform supports + // __ASSERT_ALWAYS( KUidMediaTypeAudio == aMediaId.iMediaType, + // User::Leave( KErrNotSupported ) ); + + // Cancel timer, so timer does not interrupt our current sending. + // Timer enables empty blocks to be appended when redundancy is on. + iTimer->Cancel(); + + iDataPath = aSupplier; + iSourceBuffer = static_cast( aBuffer ); + + if ( !iSinkBuffer ) + { + iStateMachine->ChangeState( ESourceBufferEmptied ); + return; + } + + if ( !iSinkBuffer->Data().Length() ) + { + //User::LeaveIfError( iRtpMediaClock->GetTimeStamp( iKey, iCurrentTimestamp ) ); + iSinkBuffer->SetTimeToPlay( TInt64( iCurrentTimestamp ) ); + iSinkBuffer->SetFrameNumber( aBuffer->FrameNumber() ); + } + + + // We signal StateMachine to ChangeState() + // this calls back EmptySourceBufferL + iStateMachine->ChangeState( EEmptySourceBuffer ); + + } + + +// ----------------------------------------------------------------------------- +// CMsrpPayloadFormatWrite::SetSinkDataTypeCode +// Set the sink data type to the given four CC code for the given media +// ----------------------------------------------------------------------------- +// +TInt CMsrpPayloadFormatWrite::SetSinkDataTypeCode( TFourCC aSinkFourCC, + TMediaId /*aMediaId*/ ) + { + DP_MSRP_WRITE("CMsrpPayloadFormatWrite::SetSinkDataTypeCode"); + /* TODO: Remove me when platform supports + if ( KUidMediaTypeText != aMediaId.iMediaType ) + { + User::Leave( KErrNotSupported ); + } + */ + iFourCC = aSinkFourCC; + return KErrNone; + + } + + +// ----------------------------------------------------------------------------- +// CMsrpPayloadFormatWrite::SinkDataTypeCode +// Return the sink data type (four CC code) for the given media ID +// ----------------------------------------------------------------------------- +// +TFourCC CMsrpPayloadFormatWrite::SinkDataTypeCode( TMediaId /*aMediaId*/ ) + { + DP_MSRP_WRITE("CMsrpPayloadFormatWrite::SinkDataTypeCode"); + /* TODO: Remove me when platform supports + if ( KUidMediaTypeText == aMediaId.iMediaType ) + { + return iFourCC; + } + else + { + return TFourCC(); //defaults to 'NULL' fourCC + } + */ + return iFourCC; + + } + +// ----------------------------------------------------------------------------- +// CMsrpPayloadFormatWrite::BufferEmptiedL +// Called after payload buffer is completely emptied by RtpDataSink. +// ----------------------------------------------------------------------------- +// +void CMsrpPayloadFormatWrite::BufferEmptiedL( CMMFBuffer* /*aBuffer*/ ) + { + DP_MSRP_WRITE( "CMsrpPayloadFormatWrite::BufferEmptiedL" ); + // nothing to be done + + //NOTE: 14.12.2007 - LeaveScan causes warning, but this is a interface method + } + + +// ----------------------------------------------------------------------------- +// CMsrpPayloadFormatWrite::FrameTimeInterval +// Return the frame time interval for the given media +// Return allways 0 +// ----------------------------------------------------------------------------- +// +TTimeIntervalMicroSeconds + CMsrpPayloadFormatWrite::FrameTimeInterval( TMediaId /*aMediaId*/ ) const + { + DP_MSRP_WRITE( "CMsrpPayloadFormatWrite::FrameTimeInterval" ); + return TTimeIntervalMicroSeconds( TInt64( 0 ) ); + } + +// ----------------------------------------------------------------------------- +// CMsrpPayloadFormatWrite::Duration +// Return the frame time interval for the given media +// NOT SUPPORTED +// ----------------------------------------------------------------------------- +// +TTimeIntervalMicroSeconds + CMsrpPayloadFormatWrite::Duration( TMediaId /*aMediaType*/ ) const + { + DP_MSRP_WRITE( "CMsrpPayloadFormatWrite::Duration" ); + return TTimeIntervalMicroSeconds( TInt64( 0 ) ); + } + + +// ----------------------------------------------------------------------------- +// CMsrpPayloadFormatWrite::EmptySourceBufferL +// Empty the given sourcebuffer +// Sourcebuffer is given in iSourceBuffer +// Called by StateMachine +// ----------------------------------------------------------------------------- +// +void CMsrpPayloadFormatWrite::EmptySourceBufferL() + { + + DP_MSRP_WRITE( "CMsrpPayloadFormatWrite::EmptySourceBufferL" ); + + const TDesC8& srcDes( iSourceBuffer->Data() ); + const TUint8* srcPtr = srcDes.Ptr(); + TInt length = iSourceBuffer->Data().Length(); + + if ( iSourceBuffer->Data().Length() ) + { + + if( KMaxRTTChunkSize < length ) + { + DP_MSRP_WRITE( "ERR - RTT Payload Length exceeded MaxChunkSize" ); + User::Leave(KErrArgument); + } + + TBuf16 unicode; + User::LeaveIfError( + CnvUtfConverter::ConvertToUnicodeFromUtf8(unicode, TPtrC8(srcPtr))); + + //buffer the user data + TStringElement buffer; + buffer.iData = unicode; + iUserBuffer->AppendL(buffer); + + FormUserDataL(); + ForwardDataL(); + + } +} + + +// ----------------------------------------------------------------------------- +// CMsrpPayloadFormatWrite::TimerExpiredL() +// Sends Redundant data after buffer period, if no user data +// appeared before that. +// ----------------------------------------------------------------------------- +// +void CMsrpPayloadFormatWrite::TimerExpiredL() +{ + DP_MSRP_WRITE( "CMsrpPayloadFormatWrite::TimerExpiredL" ); + + // Because timer expired, we must send redundant data anyway + TStringElement nullData; + iUserBuffer->AppendL(nullData); + + FormUserDataL(); + //TODO:Handle other Errors if any + TInt err = SendRedundantDataL(); + if ( err != KErrNone ) + { + GotoIdleL(); + } +} + + +// ----------------------------------------------------------------------------- +// CMsrpPayloadFormatWrite::ForwardDataL() +// Sends Redundant data after buffer period, if no user data +// appeared before that. +// ----------------------------------------------------------------------------- +// +void CMsrpPayloadFormatWrite::ForwardDataL() +{ + DP_MSRP_WRITE( "CMsrpPayloadFormatWrite::ForwardDataL" ); + + // Just Send Data + TInt err = SendRedundantDataL(); + + if ( err == KErrNone ) + { + iStateMachine->ChangeState( ESourceBufferEmptied ); + } +} + + + +// ----------------------------------------------------------------------------- +// CMsrpPayloadFormatWrite::SendRedundantDataL() +// A Method that sends the redundant buffer to Sink +// Calls CMsrpPayloadFormatWrite::DeliverPacketL +// ----------------------------------------------------------------------------- +// +TInt CMsrpPayloadFormatWrite::SendRedundantDataL() + { + DP_MSRP_WRITE( "CMsrpPayloadFormatWrite::SendRedundantDataL" ); + + TStringElement zero = iRedData->At(0); + TStringElement one = iRedData->At(1); + TStringElement two = iRedData->At(2); + + DP_MSRP_WRITE( "******************"); + DP_MSRP_WRITE2( "SendRedundantDataL - Zero Lenght: %d", zero.iData.Length() ); + DP_MSRP_WRITE2( "SendRedundantDataL - R1 Lenght: %d", one.iData.Length() ); + DP_MSRP_WRITE2( "SendRedundantDataL - R2 lenght: %d", two.iData.Length() ); + + if ( zero.iData.Length() == 0 && one.iData.Length() == 0 && two.iData.Length() == 0 ) + { + DP_MSRP_WRITE( "ERR - SendRedundantDataL - All Data is 0 lenght returning, KErrArgument!"); + return KErrArgument; + } + + TDes8& destDes( iSinkBuffer->Data() ); + + // Assemble redundant data + AssembleRedPacket(); + // Append current data to buffer + TPtr8 ptr = iBuf->Des(); + destDes.Append( ptr ); + + DP_MSRP_WRITE2( "CMsrpPayloadFormatWrite HeapData size: %d", ptr.Size() ); + DP_MSRP_WRITE2( "CMsrpPayloadFormatWrite HeapData Length: %d", ptr.Length() ); + DP_MSRP_WRITE ("CMsrpPayloadFormatWrite::DeliverPacketL, Packet Assembled" ); + DP_MSRP_WRITE( "******************"); + + DeliverPacketL( *iSinkBuffer ); + return KErrNone; + + } + + +// ----------------------------------------------------------------------------- +// CMsrpPayloadFormatWrite::FormUserDataL() +// +// A function that refreshes the RedundantData Buffer, so that +// We just can send data that is there. +// ----------------------------------------------------------------------------- +// +TInt CMsrpPayloadFormatWrite::FormUserDataL() +{ + DP_MSRP_WRITE( "CMsrpPayloadFormatWrite::SendRedundantDataL" ); + + TStringElement primary; + + // if there is data + if ( iUserBuffer->Count() ) + { + primary = iUserBuffer->At(0); + } + + //set timestamp to primary data, this is used to calculate offset + primary.iTimestamp = iSinkBuffer->TimeToPlay().Int64(); + + // can now reset user buffer + iUserBuffer->Reset(); + + // get current redundants + TStringElement zero = iRedData->At(0); + TStringElement one = iRedData->At(1); + + // we can now reset old redundant also + iRedData->Reset(); + + // re-order redundant data, this must be always present, + // if redundancy changes on-fly from e.g 0 to 2 + iRedData->AppendL(primary); + iRedData->AppendL(zero); + iRedData->AppendL(one); + + return KErrNone; +} + + +// ----------------------------------------------------------------------------- +// CMsrpPayloadFormatWrite::GoToIdleL() +// +// When there is no data to send, we must go to idle mode +// ----------------------------------------------------------------------------- +// +void CMsrpPayloadFormatWrite::GotoIdleL() + { + + DP_MSRP_WRITE( "CMsrpPayloadFormatWrite::GoToIdleL()"); + //reset redundancy buffer + iRedData->Reset(); + //add default data + TStringElement empty; + iRedData->AppendL(empty); + iRedData->AppendL(empty); + iRedData->AppendL(empty); + iIdleMode = ETrue; + + //Set State that we are waiting for Data + iStateMachine->ChangeState( EWaitForSourceData ); + + // Cancel the Timer also + iTimer->Cancel(); + + } + + +// ----------------------------------------------------------------------------- +// CMsrpPayloadFormatWrite::AssembleRedPacket() +// +// In AssembleRedPacket we must assemble right kind of +// payload. We switch between redundant and plain data. +// If redundancy is used a redundant datapacket is generated! +// ----------------------------------------------------------------------------- +// +void CMsrpPayloadFormatWrite::AssembleRedPacket() + { + DP_MSRP_WRITE( "CMsrpPayloadFormatWrite::AssembleRedPacket" ); + switch( iCodecInfo.iRedundancyCount ) + { + case 0: + // just append the primary data and no headers + iBuf->Des().Append( iRedData->At(0).iData ); + break; + + case 2: + TInt err = GenerateRedPacket(); + //TODO: Handle Errors in Creating packet + break; + + } + + } + + +// ----------------------------------------------------------------------------- +// CMsrpPayloadFormatWrite::GenerateRedPacket() +// +// In GenerateRedPacket we must assemble right kind of +// payload according to RFC 4103. Level 2 redundancy is used. +// ----------------------------------------------------------------------------- +// +TInt CMsrpPayloadFormatWrite::GenerateRedPacket() +{ + + DP_MSRP_WRITE( "CMsrpPayloadFormatWrite::GenerateRedPacket()" ); + + TStringElement primary = iRedData->At(0); + TStringElement r1 = iRedData->At(1); + TStringElement r2 = iRedData->At(2); + + DP_MSRP_WRITE( "*******************************"); + DP_MSRP_WRITE2("CMsrpPayloadFormatWrite::GenerateRedPacket PR Length: %d", primary.iData.Length() ); + DP_MSRP_WRITE2("CMsrpPayloadFormatWrite::GenerateRedPacket R1 Length: %d", r1.iData.Length() ); + DP_MSRP_WRITE2("CMsrpPayloadFormatWrite::GenerateRedPacket R2 Length: %d", r2.iData.Length() ); + + // pointer to data + TUint8* dataP = iData; + TInt count(0); + //Fill Data with binary zeroes and zero old + Mem::FillZ( dataP, KRedHeaderSize + KDataSize ); + iBuf->Des().Zero(); + + + /************* + data[0] = 8 bit + 1 bit - redundancy marker bit 1 + 7 bit - payloadtype + ***************/ + + iData[0] |= ( 1 << 7 ); + iData[0] |= iCodecInfo.iRedundantPayload; + //iData[0] |= 106; + dataP += 1; + count ++; + + + /************** + data[1-3] = 24 bit + 14 bit - timestamp offset of R2 + 10 bit - length of R2 + ***************/ + + TUint32 temp(0); + temp |= ( SetTimeOffset(primary.iTimestamp, r2.iTimestamp ) << 10 ); + + TUint16 size(r2.iData.Length()); + temp |= size; + + Write24(dataP, temp); + dataP += 3; + count += 3; + + DP_MSRP_WRITE2( "CMsrpPayloadFormatWrite::GenerateRedPacket DATA[0]: %x", iData[0] ); + DP_MSRP_WRITE2( "CMsrpPayloadFormatWrite::GenerateRedPacket DATA[1]: %x", iData[1] ); + DP_MSRP_WRITE2( "CMsrpPayloadFormatWrite::GenerateRedPacket DATA[2]: %x", iData[2] ); + DP_MSRP_WRITE2( "CMsrpPayloadFormatWrite::GenerateRedPacket DATA[3]: %x", iData[3] ); + + + /************** + data[4] = 8 bit + 1 bit - redundancy marker bit 1 + 7 bit - payloadtype + ***************/ + + iData[4] |= ( 1 << 7 ); + iData[4] |= iCodecInfo.iRedundantPayload; + //iData[4] |= 106; + dataP += 1; + count ++; + + /************** + data[5-7] = 24 bit + 14 bit - timestamp offset of R1 + 10 bit - length of R1 + ***************/ + + temp = 0; + temp |= ( SetTimeOffset(primary.iTimestamp, r1.iTimestamp ) << 10 ); + + size = r1.iData.Length(); + temp |= size; + + Write24(dataP, temp); + dataP += 3; + count += 3; + + /************** + data[8] = 8 bit + 1 bit - normal marker bit 0 + 7 bit - payloadtype + ***************/ + iData[8] |= ( 0 << 7 ); + iData[8] |= iCodecInfo.iPayloadType; + //iData[8] |= 105; + dataP += 1; + count ++; + + DP_MSRP_WRITE2( "CMsrpPayloadFormatWrite::GenerateRedPacket DATA[4]: %x", iData[4] ); + DP_MSRP_WRITE2( "CMsrpPayloadFormatWrite::GenerateRedPacket DATA[5]: %x", iData[5] ); + DP_MSRP_WRITE2( "CMsrpPayloadFormatWrite::GenerateRedPacket DATA[6]: %x", iData[6] ); + DP_MSRP_WRITE2( "CMsrpPayloadFormatWrite::GenerateRedPacket DATA[7]: %x", iData[7] ); + DP_MSRP_WRITE2( "CMsrpPayloadFormatWrite::GenerateRedPacket DATA[8]: %x", iData[8] ); + DP_MSRP_WRITE( "*******************************"); + + //TODO: When IOP-Tests Are done, Write me properly using Append, or some other method + TInt forHere = count+r2.iData.Length(); + TInt index(0); + if ( r2.iData.Length() ) + { + for ( TInt i = count; i < forHere; i++ ) + { + iData[i] = r2.iData[index]; + index++, + RDebug::Print( _L(" X Writing R2 DATA[i]: %x"), iData[i] ); + } + + dataP += r2.iData.Length(); + count += r2.iData.Length(); + } + + + forHere = count+r1.iData.Length(); + index = 0; + if ( r1.iData.Length() ) + { + for ( TInt i = count; i < forHere; i++ ) + { + iData[i] = r1.iData[index]; + index++; + RDebug::Print( _L(" X Writing R1 DATA[i]: %x"), iData[i] ); + } + + dataP += r1.iData.Length(); + count += r1.iData.Length(); + } + + + forHere = count+primary.iData.Length(); + index = 0; + if ( primary.iData.Length() ) + { + for ( TInt i = count; i < forHere; i++ ) + { + iData[i] = primary.iData[index]; + index++; + RDebug::Print( _L(" X Writing PRIMARY DATA[i]: %x"), iData[i] ); + } + + dataP += primary.iData.Length(); + count += primary.iData.Length(); + } + + + DP_MSRP_WRITE2( "CMsrpPayloadFormatWrite::GenerateRedPacket Writing Lenght: %d", count ); + iBuf->Des().Append( iData, count ); + return KErrNone; + +} + + +// ----------------------------------------------------------------------------- +// CMsrpPayloadFormatWrite::DeliverPacketL +// Prepare the packet header and deliver the packet to the datasink. +// ----------------------------------------------------------------------------- +void CMsrpPayloadFormatWrite::DeliverPacketL( CMMFDataBuffer& aPayload ) + { + + DP_MSRP_WRITE("CMsrpPayloadFormatWrite::DeliverPacketL"); + + if ( !iClip ) + { + User::Leave( KErrNotReady ); + } + const TMediaId mediaId( KUidMediaTypeAudio ); + const TInt dataSize( aPayload.Data().Size() ); + DP_MSRP_WRITE2( "MSRP Payload SIZE : %d", dataSize ); + + if ( dataSize ) + { + if (iIsMsrpSink) + { + iMsrpDataSink->EmptyBufferL( &aPayload, this, mediaId ); + } + } + aPayload.Data().Zero(); + } + + +// ----------------------------------------------------------------------------- +// CMsrpPayloadFormatWrite::SourceBufferEmptiedL +// Handle the event that sourcebuffer has been emptied. +// Sourcebuffer is given in "iSourceBuffer". +// Called by the statemachine. +// ----------------------------------------------------------------------------- +void CMsrpPayloadFormatWrite::SourceBufferEmptiedL() + { + + + DP_MSRP_WRITE( "CMsrpPayloadFormatWrite::SourceBufferEmptiedL" ); + + //Empty all + iSourceBuffer->Data().FillZ(); + iSourceBuffer->Data().Zero(); + iSinkBuffer->Data().FillZ(); + iSinkBuffer->Data().Zero(); + iBuf->Des().FillZ(); + iBuf->Des().Zero(); + iDataPath->BufferEmptiedL( iSourceBuffer ); + + //Finally we set the timer if we are in red mode + switch( iCodecInfo.iRedundancyCount ) + { + case 0: + // do nothing + break; + + case 2: + if ( iIdleMode ) + { + iTimer->Cancel(); + iTimer->Start(); + } + break; + } + + // we are no more in idle, + iIdleMode = EFalse; + +} + + +// ----------------------------------------------------------------------------- +// CMsrpPayloadFormatWrite::SinkPrimeL +// Prime the sink +// ----------------------------------------------------------------------------- +// +void CMsrpPayloadFormatWrite::SinkPrimeL() + { + DP_MSRP_WRITE("CMsrpPayloadFormatWrite::SinkPrimeL()"); + iClip->SinkPrimeL(); + } + + +// ----------------------------------------------------------------------------- +// CMsrpPayloadFormatWrite::SinkPrimeL +// Prime the sink +// ----------------------------------------------------------------------------- +// +void CMsrpPayloadFormatWrite::CancelUlRequest() + { + + DP_MSRP_WRITE("CMsrpPayloadFormatWrite::CancelUlRequest()" ); + iStateMachine->Cancel(); + iStateMachine->ChangeState( EEncodeIdle ); + + // Reset the payload buffer + if ( iSinkBuffer ) + { + TDes8& dataDes = static_cast( iSinkBuffer )->Data(); + dataDes.SetLength( 0 ); + } + + } + + +// ----------------------------------------------------------------------------- +// CMsrpPayloadFormatWrite::SinkPlayL +// Start playing. +// ----------------------------------------------------------------------------- +// +void CMsrpPayloadFormatWrite::SinkPlayL() + { + DP_MSRP_WRITE("CMsrpPayloadFormatWrite::SinkPlayL" ); + // Allocate buffer for data transfer between + // FormatWrite - MDataSink + delete iSinkBuffer; + iSinkBuffer = NULL; + iSinkBuffer = CMMFDataBuffer::NewL( KRedHeaderSize + KDataSize ); + + // Start state machine + iStateMachine->ChangeState( EWaitForSourceData ); + + iFirstPacketFinished = EFalse; + + // Start a new cycle of frame collecting + if ( iSinkBuffer ) + { + iSinkBuffer->SetLastBuffer( EFalse ); + } + + iClip->SinkPlayL(); + } + + +// ----------------------------------------------------------------------------- +// CMsrpPayloadFormatWrite::SinkPauseL +// Pause sink +// ----------------------------------------------------------------------------- +// +void CMsrpPayloadFormatWrite::SinkPauseL() + { + DP_MSRP_WRITE("CMsrpPayloadFormatWrite::SinkPauseL" ); + this->CancelUlRequest(); + iClip->SinkPauseL(); + + } + +// ----------------------------------------------------------------------------- +// CMsrpPayloadFormatWrite::SinkStopL +// Stop sink +// ----------------------------------------------------------------------------- +// +void CMsrpPayloadFormatWrite::SinkStopL() + { + DP_MSRP_WRITE("CMsrpPayloadFormatWrite::SinkPauseL" ); + // Stop state machine + this->CancelUlRequest(); + iClip->SinkStopL(); + } + + +// --------------------------------------------------------------------------- +// CMsrpPayloadFormatWrite::ConfigurePayloadFormatL +// Configure payload encoding parameters +// --------------------------------------------------------------------------- +// +void CMsrpPayloadFormatWrite::ConfigurePayloadFormatL( const TDesC8& aConfigParams, + CMccRtpMediaClock& /*aClock*/ ) + { + DP_MSRP_WRITE( "CMsrpPayloadFormatWrite::ConfigurePayloadFormatL()" ); + + //Check that buffer is same size, so we can assume data is correct type + __ASSERT_ALWAYS( aConfigParams.Size() == sizeof( TMccCodecInfo ), + User::Leave( KErrArgument ) ); + + //instantiate correct CodecInfo Structure + TMccCodecInfoBuffer infoBuffer; + infoBuffer.Copy( aConfigParams ); + TMccCodecInfo codecInfo( infoBuffer() ); + + if ( !codecInfo.iIsUpdate ) + { + + //iCodecInfo = codecInfo; + //iRtpMediaClock = &aClock; + //iKey = iRtpMediaClock->RegisterMediaFormat( KDefaultSampleRate, iCodecInfo.iHwFrameTime ); + } + else + { + UpdateConfigurationL( aConfigParams ); + } + + } + +// ----------------------------------------------------------------------------- +// CMsrpPayloadFormatWrite::UpdateConfigurationL +// Update payload encoding parameters +// ----------------------------------------------------------------------------- +// +void CMsrpPayloadFormatWrite::UpdateConfigurationL( const TDesC8& aConfigParams ) + { + DP_MSRP_WRITE( "CMsrpPayloadFormatWrite::UpdateConfigurationL" ); + __ASSERT_ALWAYS( aConfigParams.Size() == sizeof( TMccCodecInfo ), + User::Leave( KErrArgument ) ); + + TMccCodecInfoBuffer infoBuffer; + infoBuffer.Copy( aConfigParams ); + TMccCodecInfo codecInfo = infoBuffer(); + + iCodecInfo = codecInfo; + //iCodecInfo.iPtime = codecInfo.iPtime; + //iCodecInfo.iRedundancyCount = 0; + + //iCodecInfo.iPayloadType = codecInfo.iPayloadType; + //iCodecInfo.iRedundancyCount = codecInfo.iRedundancyCount; + //iCodecInfo.iCodecMode = codecInfo.iCodecMode; + + //TODO: move me to right variable and update buffering time + //iTimer->Cancel(); + //iTimer->SetTimeOut( iCodecInfo.iCodecMode * 1000); + + // Allocate buffer for data transfer between + // FormatWrite - MDataSink + delete iSinkBuffer; + iSinkBuffer = NULL; + iSinkBuffer = CMMFDataBuffer::NewL( KRedHeaderSize + KDataSize ); + + } + + + +// ========================== HELPER FUNCTIONS ========================= +// ========================== ========================= +// ========================== ========================= + +// ----------------------------------------------------------------------------- +// CMsrpPayloadFormatWrite::Write24 +// Simple helper function, that writes a 24-bit value to databuffer, +// using pointer +// ----------------------------------------------------------------------------- +// +void CMsrpPayloadFormatWrite::Write24( TUint8* const aPointer, TUint32 aValue ) + { + DP_MSRP_WRITE( "CMsrpPayloadFormatWrite::Write24" ); + aPointer[0] = static_cast( ( aValue & 0xFF0000 ) >> 16 ); + aPointer[1] = static_cast( ( aValue & 0x00FF00 ) >> 8 ); + aPointer[2] = static_cast( aValue & 0x0000FF ); + } + + +// ----------------------------------------------------------------------------- +// CMsrpPayloadFormatWrite::Write32 +// Simple helper function, that writes a 32-bit value to databuffer, +// using pointer +// ----------------------------------------------------------------------------- +// +void CMsrpPayloadFormatWrite::Write32( TUint8* const aPointer, TUint32 aValue ) + { + DP_MSRP_WRITE( "CMsrpPayloadFormatWrite::Write32" ); + aPointer[0] = static_cast( ( aValue & 0xFF000000 ) >> 24 ); + aPointer[1] = static_cast( ( aValue & 0x00FF0000 ) >> 16 ); + aPointer[2] = static_cast( ( aValue & 0x0000FF00 ) >> 8 ); + aPointer[3] = static_cast( aValue & 0x000000FF ); + } + + +// ----------------------------------------------------------------------------- +// CMsrpPayloadFormatWrite::SetTimeOffset +// Calculates TimeOffset to RedundancyHeader according to +// RFC 4103. Actually RFC 4103 does not accurately state how ( and where ) +// timeoffset should be calculated. This calculation is based conversations +// with authors of RFC 4103 +// ----------------------------------------------------------------------------- +// +TUint16 CMsrpPayloadFormatWrite::SetTimeOffset( TInt64& aPrim, TInt64& aSecond ) +{ + DP_MSRP_WRITE( "CMsrpPayloadFormatWrite::SetTimeOffset" ); + TInt pOffset = aPrim - aSecond; + TUint16 aRet = TUint16(pOffset) & KHighestTimeStampOffset; + if( aRet > KHighestTimeStampOffset ) + { + aRet = KHighestTimeStampOffset; + } + return aRet; +} + + +TStringElement::TStringElement() +{ +} + + +// End of File