diff -r 000000000000 -r 1bce908db942 multimediacommscontroller/mmccg729payloadformat/src/g729payloadformatread.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/multimediacommscontroller/mmccg729payloadformat/src/g729payloadformatread.cpp Tue Feb 02 01:04:58 2010 +0200 @@ -0,0 +1,1166 @@ +/* +* 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: PayloadFormat plugin capable to read RTP payload containing +* G729 audio. +* +*/ + + + + +// INCLUDE FILES + +#include "g729payloadformatread.h" +#include "g729payloadformatutil.h" +#include "mccrtpdatasource.h" +#include "formatstatemachine.h" +#include "streamformatter.h" +#include "mccinternaldef.h" +#include "mccredpayloadread.h" + +#ifdef VOIP_TRACE_ENABLED +#include +#endif + +// ============================= LOCAL FUNCTIONS =============================== + +// ============================ MEMBER FUNCTIONS =============================== + + +// ----------------------------------------------------------------------------- +// CG729PayloadFormatRead::CG729PayloadFormatRead +// C++ default constructor can NOT contain any code, that +// might leave. +// ----------------------------------------------------------------------------- +// +CG729PayloadFormatRead::CG729PayloadFormatRead() + { + } + +// ----------------------------------------------------------------------------- +// CG729PayloadFormatRead::ConstructL +// Symbian 2nd phase constructor can leave. +// ----------------------------------------------------------------------------- +// +void CG729PayloadFormatRead::ConstructL( MDataSource* aSource ) + { + #ifdef VOIP_TRACE_ENABLED + VoipTrace( "%x %x %x", MCC_TRACE, MCC_G711_PLF_READ_CONSTRUCTL, aSource ); + #endif + __ASSERT_ALWAYS( aSource, User::Leave( KErrArgument ) ); + + iClip = aSource; + iBufferToReadExists = EFalse; + + iFourCC.Set( KMccFourCCIdG729 ); + + // Initialize decoding state machine + iStateMachine = CFormatDecodeStateMachine::NewL( this ); + iCurrentBuffer = EBufferOne; + } + +// ----------------------------------------------------------------------------- +// CG729PayloadFormatRead::NewL +// Two-phased constructor. +// ----------------------------------------------------------------------------- +// +CG729PayloadFormatRead* CG729PayloadFormatRead::NewL( MDataSource* aSource ) + { + #ifdef TRACE_G729_PAYLOAD_FORMAT_READ + RDebug::Print (_L ("CG729PayloadFormatRead::NewL()")); + #endif + #ifdef VOIP_TRACE_ENABLED + VoipTrace( "%x %x %x", MCC_TRACE, MCC_G711_PLF_READ_NEWL, aSource ); + #endif + + __ASSERT_ALWAYS( aSource, User::Leave( KErrArgument ) ); + + CG729PayloadFormatRead* self = new (ELeave) CG729PayloadFormatRead; + CleanupStack::PushL( self ); + self->ConstructL( aSource ); + CleanupStack::Pop( self ); + return self; + } + +// ----------------------------------------------------------------------------- +// CG729PayloadFormatRead::~CG729PayloadFormatRead() +// Destructor. +// ----------------------------------------------------------------------------- +// +CG729PayloadFormatRead::~CG729PayloadFormatRead() + { + #ifdef TRACE_G729_PAYLOAD_FORMAT_READ + RDebug::Print (_L ("CG729PayloadFormatRead::\ + ~CG729PayloadFormatRead()")); + #endif + #ifdef VOIP_TRACE_ENABLED + VoipTrace( "%x %x", MCC_TRACE, MCC_G711_PLF_READ_DESTRUCTOR ); + #endif + + delete iFrameBufferOne; + delete iFrameBufferTwo; + if ( iSourceBufOwnership ) + { + delete iSourceBuffer; + } + else + { + iSourceBuffer = NULL; + } + + if ( iStateMachine ) + { + iStateMachine->Cancel(); + delete iStateMachine; + } + + iClip = NULL; + iDataPath = NULL; + iClip = NULL; + + iFrameArray.Close(); + } + + +// ----------------------------------------------------------------------------- +// CG729PayloadFormatRead::SendDataToSinkL +// Send full frame buffer to the DataPath. +// ----------------------------------------------------------------------------- +// +void CG729PayloadFormatRead::SendDataToSinkL() + { + #ifdef VOIP_TRACE_ENABLED + VoipTrace( "%x %x", MCC_TRACE, MCC_G711_PLF_READ_SENDDATATOSINKL ); + #endif + + if ( EBufferOne == iCurrentBuffer ) + { + #ifdef TRACE_G729_PAYLOAD_FORMAT_READ + RDebug::Print (_L ("CG729PayloadFormatRead::\ + SendDataToSinkL() - BufferOne")); + #endif + + iDataPath->BufferFilledL( iFrameBufferOne); + iCurrentBuffer = EBufferTwo; + // More payload buffers needed + if ( iBufferToReadExists && !iFrameBufferOne->LastBuffer() ) + { + iStateMachine->ChangeState( ESourceDataReady ); + } + } + else + { + #ifdef TRACE_G729_PAYLOAD_FORMAT_READ + RDebug::Print (_L ("CG729PayloadFormatRead::\ + SendDataToSinkL() - BufferTwo")); + #endif + + iDataPath->BufferFilledL( iFrameBufferTwo ); + iCurrentBuffer = EBufferOne; + // More payload buffers needed + if ( iBufferToReadExists && !iFrameBufferTwo->LastBuffer() ) + { + iStateMachine->ChangeState( ESourceDataReady ); + } + } + + #ifdef TRACE_G729_PAYLOAD_FORMAT_READ + RDebug::Print (_L ("CG729PayloadFormatRead::SendDataToSinkL() - DONE") ); + #endif + } + +// ----------------------------------------------------------------------------- +// CG729PayloadFormatRead::FillSinkBuffer +// Fill SinkBuffer. +// ----------------------------------------------------------------------------- +// +void CG729PayloadFormatRead::FillSinkBufferL() + { + #ifdef VOIP_TRACE_ENABLED + VoipTrace( "%x %x", MCC_TRACE, MCC_G711_PLF_READ_FILLSINKBUFFER ); + #endif + + CMMFDataBuffer* curFrameBuffer; + if ( EBufferOne == iCurrentBuffer ) + { + #ifdef TRACE_G729_PAYLOAD_FORMAT_READ + RDebug::Print( _L("G729PayloadFormatRead:FillSinkBuffer() EBufferOne \ + reqsize: %d"), iFrameBufferOne->RequestSize() ); + #endif + + curFrameBuffer = iFrameBufferOne; + } + else + { + #ifdef TRACE_G729_PAYLOAD_FORMAT_READ + RDebug::Print( _L("G729PayloadFormatRead:FillSinkBuffer() EBufferOne \ + reqsize: %d"), iFrameBufferTwo->RequestSize() ); + #endif + + curFrameBuffer = iFrameBufferTwo; + } + + TDes8& curFrameData = curFrameBuffer->Data(); + curFrameData.Zero(); + + // Put next frame decoded from RTP payload to the framebuffer + this->GetNextFrame( curFrameData ); + + HBufC8* buffer = NULL; + buffer = curFrameData.Alloc(); + curFrameData.SetLength( KG729NumOfHeaderBytes ); + TBool sidFrame = EFalse; + + // Check the audio frame length, if we have one + TInt frameLen = 0; + if( buffer ) + { + frameLen = buffer->Length(); + } + + if ( KG729FrameSize10ms == frameLen ) + { + #ifdef TRACE_G729_PAYLOAD_FORMAT_READ + RDebug::Print( _L ("CG729PayloadFormatRead::FillSinkBuffer ADD AUDIO HEADER") ); + #endif + + // Add 1st G.729 header byte for audio + curFrameData[0] = KAudioFrameHeaderByte; + sidFrame = EFalse; + } + else if( KG729CNFrameSize == frameLen ) + { + #ifdef TRACE_G729_PAYLOAD_FORMAT_READ + RDebug::Print( _L ("CG729PayloadFormatRead::FillSinkBuffer ADD SID HEADER") ); + #endif + + // Add 1st G.729 header byte for SID frame + curFrameData[0] = KCNoiseFrameHeaderByte; + sidFrame = ETrue; + } + else + { + #ifdef TRACE_G729_PAYLOAD_FORMAT_READ + RDebug::Print( _L ("CG729PayloadFormatRead::FillSinkBuffer UNKNOWN FRAMELEN: %d"), frameLen ); + #endif + + // delete the buffer as something is badly wrong, this will be handled + // a bit later on + delete buffer; + buffer = NULL; + } + + if( buffer ) + { + // Add 2nd G.729 header byte to the frame going to the decoder, + // always zero + curFrameData[1] = 0; + + this->DoBitUnPacking( *buffer, curFrameData, sidFrame ); + delete buffer; + buffer = NULL; + } + else + { + #ifdef TRACE_G729_PAYLOAD_FORMAT_READ + RDebug::Print( _L ("CG729PayloadFormatRead::FillSinkBuffer NO AUDIOBUFFER") ); + #endif + + // May be that the allocation failed or GetNextFrame() returned a + // unknown size frame. In this case, fill the reset of the curFrameData + // with zeroes like it would be a normal G.729 frame. + curFrameData.SetLength( KG729CodecDecBufSize ); + + // This will set the header bytes to zero meaning a 0bit/s frame, which + // is fine with the decoder. + curFrameData.FillZ(); + } + + curFrameBuffer->SetFrameNumber( iRecvHeader.iTimestamp + ( ( iFrameIndex - 1 ) + * TUint( iCInfo.iHwFrameTime * KG729SampleRate * 0.001 ) ) ); + + curFrameBuffer->SetStatus( EFull ); + + iStateMachine->ChangeState( EEmptyDataToSink ); + + #ifdef TRACE_G729_PAYLOAD_FORMAT_READ + RDebug::Print( _L("G729PayloadFormatRead::FillSinkBuffer() \ + BUFSZ: %d"), curFrameBuffer->BufferSize() ); + #endif + } + +// ----------------------------------------------------------------------------- +// CG729PayloadFormatRead::FillSourceBufferL +// Send fill buffer request to the RTP Data Source. +// ----------------------------------------------------------------------------- +// +void CG729PayloadFormatRead::FillSourceBufferL() + { + #ifdef TRACE_G729_PAYLOAD_FORMAT_READ + RDebug::Print (_L ("CG729PayloadFormatRead::FillSourceBufferL()")); + #endif + #ifdef VOIP_TRACE_ENABLED + VoipTrace( "%x %x", MCC_TRACE, MCC_G711_PLF_READ_FILLSOURCEBUFFERL ); + #endif + + // RtpSourceSink doesn't really need the Media Id. + iClip->FillBufferL( iSourceBuffer, this, iMediaId ); + } + +// ----------------------------------------------------------------------------- +// CG729PayloadFormatRead::SourcePrimeL +// Prime source. +// ----------------------------------------------------------------------------- +// +void CG729PayloadFormatRead::SourcePrimeL() + { + #ifdef TRACE_G729_PAYLOAD_FORMAT_READ + RDebug::Print( _L("CG729PayloadFormatRead::SourcePrimeL") ); + #endif + #ifdef VOIP_TRACE_ENABLED + VoipTrace( "%x %x", MCC_TRACE, MCC_G711_PLF_READ_SOURCEPRIMEL ); + #endif + + iClip->SourcePrimeL(); + } + +// ----------------------------------------------------------------------------- +// CG729PayloadFormatRead::SourcePlayL +// Start playing. +// ----------------------------------------------------------------------------- +// +void CG729PayloadFormatRead::SourcePlayL() + { + #ifdef TRACE_G729_PAYLOAD_FORMAT_READ + RDebug::Print( _L("CG729PayloadFormatRead::SourcePlayL") ); + #endif + #ifdef VOIP_TRACE_ENABLED + VoipTrace( "%x %x", MCC_TRACE, MCC_G711_PLF_READ_SOURCEPLAYL ); + #endif + + iClip->SourcePlayL(); + } + +// ----------------------------------------------------------------------------- +// CG729PayloadFormatRead::SourcePauseL +// Pause source. +// ----------------------------------------------------------------------------- +// +void CG729PayloadFormatRead::SourcePauseL() + { + #ifdef TRACE_G729_PAYLOAD_FORMAT_READ + RDebug::Print( _L("CG729PayloadFormatRead::SourcePauseL") ); + #endif + #ifdef VOIP_TRACE_ENABLED + VoipTrace( "%x %x", MCC_TRACE, MCC_G711_PLF_READ_SOURCEPAUSEL ); + #endif + + iStateMachine->Cancel(); + iStateMachine->ChangeState( EDecodeIdle ); + + iFrameBufferOne->SetLastBuffer( EFalse ); + iFrameBufferTwo->SetLastBuffer( EFalse ); + + iFrameBufferOne->SetStatus( EAvailable ); + iFrameBufferTwo->SetStatus( EAvailable ); + + iBufferToReadExists = EFalse; + iCurrentBuffer = EBufferOne; + + iClip->SourcePauseL(); + } + +// ----------------------------------------------------------------------------- +// CG729PayloadFormatRead::SourceStopL +// Stop source +// ----------------------------------------------------------------------------- +// +void CG729PayloadFormatRead::SourceStopL() + { + #ifdef TRACE_G729_PAYLOAD_FORMAT_READ + RDebug::Print( _L("CG729PayloadFormatRead::SourceStopL") ); + #endif + #ifdef VOIP_TRACE_ENABLED + VoipTrace( "%x %x", MCC_TRACE, MCC_G711_PLF_READ_SOURCESTOPL ); + #endif + + // DO NOT RESET PACKET COUNT BACK TO ZERO HERE + // UPPER LAYER MAY CALL LastDlPacketCount LATER + + iStateMachine->Cancel(); + + iStateMachine->ChangeState( EDecodeIdle ); + + iFrameBufferOne->SetLastBuffer( EFalse ); + iFrameBufferTwo->SetLastBuffer( EFalse ); + + iFrameBufferOne->SetStatus( EAvailable ); + iFrameBufferTwo->SetStatus( EAvailable ); + + iBufferToReadExists = EFalse; + iCurrentBuffer = EBufferOne; + + #ifdef DEBUG_G729_INTERVAL + RDebug::Print( _L("Processed %d G729 frames"), iFrameCount ); + iFrameCount = 0; + #endif + + iClip->SourceStopL(); + } + +// ----------------------------------------------------------------------------- +// CG729PayloadFormatRead::BufferFilledL +// RTP data source has filled buffer. +// NOTE: Although redundancy is negotiated, sender may deside to send audio +// packets without redundancy (RFC2198, ch5). +// ----------------------------------------------------------------------------- +// +void CG729PayloadFormatRead::DataBufferFilledL( CMMFBuffer* aBuffer, const TRtpRecvHeader &aRecvHeader) + { + #ifdef TRACE_G729_PAYLOAD_FORMAT_READ + RDebug::Print( _L("CG729PayloadFormatRead::DataBufferFilledL - TSTAMP: %u"), + aRecvHeader.iTimestamp ); + #endif + __ASSERT_ALWAYS( aBuffer, User::Leave( KErrArgument ) ); + __ASSERT_ALWAYS( KUidMmfDataBuffer == aBuffer->Type(), + User::Leave( KErrNotSupported ) ); + __ASSERT_ALWAYS( iSourceBuffer == aBuffer, User::Leave( KErrArgument ) ); + + // Copy received buffer + TDes8& destDes = iSourceBuffer->Data(); + + iRecvHeader = aRecvHeader; + + // Decode data blocks + DecodePayload( destDes ); + + // Whenever BufferFilledL is called from RtpSourceSink + // Set the state machine to fillsinkbuffer + if ( iFrameArray.Count() ) + { + iBufferToReadExists = ETrue; + iSourceBuffer->SetFrameNumber( iRecvHeader.iTimestamp ); + iStateMachine->ChangeState( ESourceDataReady ); + } + else + { + #ifdef TRACE_G729_PAYLOAD_FORMAT_READ + RDebug::Print( _L("CG729PayloadFormatRead::BufferFilledL, decode failed" ) ); + #endif + + FillSourceBufferL(); + } + } + +// ----------------------------------------------------------------------------- +// CG729PayloadFormatRead::SampleRate +// Returns samplerate. +// ----------------------------------------------------------------------------- +// +TUint CG729PayloadFormatRead::SampleRate() + { + return KG729SampleRate; + } + +// ----------------------------------------------------------------------------- +// CG729PayloadFormatRead::SetSampleRate +// Set samplerate. +// ----------------------------------------------------------------------------- +// +TInt CG729PayloadFormatRead::SetSampleRate( TUint aSampleRate ) + { + #ifdef VOIP_TRACE_ENABLED + VoipTrace( "%x %x %d", MCC_TRACE, MCC_G711_PLF_READ_SETSAMPLERATE, + aSampleRate ); + #endif + + return ( KG729SampleRate == aSampleRate ) ? KErrNone : KErrNotSupported; + } + +// ----------------------------------------------------------------------------- +// CG729PayloadFormatRead::NumChannels +// Returns number of channels. +// ----------------------------------------------------------------------------- +// +TUint CG729PayloadFormatRead::NumChannels() + { + return KMono; + } + +// ----------------------------------------------------------------------------- +// CG729PayloadFormatRead::SourceThreadLogon +// Logon to the source thread. +// ----------------------------------------------------------------------------- +// +TInt CG729PayloadFormatRead::SourceThreadLogon( + MAsyncEventHandler& aEventHandler ) + { + #ifdef VOIP_TRACE_ENABLED + VoipTrace( "%x %x", MCC_TRACE, MCC_G711_PLF_READ_SOURCETHREADLOGOFF ); + #endif + + if ( iClip ) + { + iClip->SourceThreadLogon( aEventHandler ); + return KErrNone; + } + else + { + return KErrNotReady; + } + } + +// ----------------------------------------------------------------------------- +// CG729PayloadFormatRead::SourceThreadLogoff +// Logout the source thread. +// ----------------------------------------------------------------------------- +// +void CG729PayloadFormatRead::SourceThreadLogoff() + { + #ifdef VOIP_TRACE_ENABLED + VoipTrace( "%x %x", MCC_TRACE, MCC_G711_PLF_READ_NEGOTIATESOURCEL ); + #endif + iClip->SourceThreadLogoff(); + } + +// ----------------------------------------------------------------------------- +// CG729PayloadFormatRead::NegotiateSourceL +// Negotiate Source. +// ----------------------------------------------------------------------------- +// +void CG729PayloadFormatRead::NegotiateSourceL(MDataSink& aDataSink) + { + #ifdef VOIP_TRACE_ENABLED + VoipTrace( "%x %x %d", MCC_TRACE, MCC_G711_PLF_READ_SOURCETHREADLOGON, + iCInfo.iRedundancyCount ); + #endif + + iDataPath = &aDataSink; + iClip->NegotiateSourceL( *this ); + } + +// ----------------------------------------------------------------------------- +// CG729PayloadFormatRead::SetSourceDataTypeCode +// Sets source datatype fourCC code +// ----------------------------------------------------------------------------- +// +TInt CG729PayloadFormatRead::SetSourceDataTypeCode( TFourCC aSourceFourCC, + TMediaId aMediaId ) + { + #ifdef TRACE_G729_PAYLOAD_FORMAT_READ + RDebug::Print (_L ("CG729PayloadFormatRead::SetSourceDataTypeCode()")); + #endif + #ifdef VOIP_TRACE_ENABLED + VoipTrace( "%x %x %d", MCC_TRACE, MCC_G711_PLF_READ_SETSOURCEDATATYPECODE, + aSourceFourCC.FourCC() ); + #endif + + if ( KUidMediaTypeAudio != aMediaId.iMediaType ) + { + return KErrNotSupported; + } + + iFourCC = aSourceFourCC; + iMediaId = aMediaId; + + iClip->SetSourceDataTypeCode( iFourCC, iMediaId ); + + return KErrNone; + } + +// ----------------------------------------------------------------------------- +// CG729PayloadFormatRead::SourceDataTypeCode +// Returns the current datatype FourCC code. +// ----------------------------------------------------------------------------- +// +TFourCC CG729PayloadFormatRead::SourceDataTypeCode( TMediaId aMediaId ) + { + if ( KUidMediaTypeAudio == aMediaId.iMediaType ) + { + return iFourCC; + } + else + { + return TFourCC(); //defaults to 'NULL' fourCC + } + } + +// ----------------------------------------------------------------------------- +// CG729PayloadFormatRead::SinkDataTypeCode +// Returns the current datatype FourCC code. +// ----------------------------------------------------------------------------- +// +TFourCC CG729PayloadFormatRead::SinkDataTypeCode( TMediaId aMediaId ) + { + if ( KUidMediaTypeAudio == aMediaId.iMediaType ) + { + return iFourCC; + } + else + { + return TFourCC(); //defaults to 'NULL' fourCC + } + } + +// ----------------------------------------------------------------------------- +// CG729PayloadFormatRead::CreateSourceBufferL +// Create a source buffer for the given media and indicate in aReference if +// buffer is created. +// ----------------------------------------------------------------------------- +// +CMMFBuffer* CG729PayloadFormatRead::CreateSourceBufferL( TMediaId aMediaId, + TBool &aReference ) + { + #ifdef VOIP_TRACE_ENABLED + VoipTrace( "%x %x", MCC_TRACE, MCC_G711_PLF_READ_CREATESOURCEBUFFERL ); + #endif + + if ( KUidMediaTypeAudio != aMediaId.iMediaType ) + { + User::Leave( KErrNotSupported ); + } + + // The source buffers belong to G729PayloadFormatRead, not to datapath + // reference should be set to ETrue and destroyed by G729PayloadFormatRead + // itself. + aReference = ETrue; + return iFrameBufferOne; + } + +// ----------------------------------------------------------------------------- +// CG729PayloadFormatRead::CreateSourceBufferL +// Create a source buffer for the given media, setting frame size to match +// the given sink buffer. +// ----------------------------------------------------------------------------- +// +CMMFBuffer* CG729PayloadFormatRead::CreateSourceBufferL(TMediaId aMediaId, + CMMFBuffer& + /*aSinkBuffer*/, + TBool& aReference) + { + #ifdef VOIP_TRACE_ENABLED + VoipTrace( "%x %x", MCC_TRACE, MCC_G711_PLF_READ_CREATESOURCEBUFFERL ); + #endif + + if ( KUidMediaTypeAudio != aMediaId.iMediaType ) + { + User::Leave( KErrNotSupported ); + } + + return CreateSourceBufferL( aMediaId, aReference ); + } + +// ----------------------------------------------------------------------------- +// CG729PayloadFormatRead::FillBufferL +// Fill Buffer. +// ----------------------------------------------------------------------------- +// +void CG729PayloadFormatRead::FillBufferL( CMMFBuffer* aBuffer, + MDataSink* aConsumer, TMediaId aMediaId ) + { + if ( !aBuffer ) + { + User::Leave( KErrGeneral ); + } + + #ifdef TRACE_G729_PAYLOAD_FORMAT_READ + RDebug::Print (_L ("CG729PayloadFormatRead::FillBufferL() \ + buffer 0x%x passed in with length %d bytes \n"), + aBuffer, aBuffer->BufferSize() ); + #endif + + if ( KUidMediaTypeAudio != aMediaId.iMediaType ) + { + User::Leave( KErrNotSupported ); + } + + if ( KUidMmfDataBuffer != aBuffer->Type() ) + { + User::Leave( KErrNotSupported ); + } + + iDataPath = aConsumer; + iMediaId = aMediaId; + + // aBuffer is a reference to those frame buffers that + // G729PayloadFormatRead owns + aBuffer->SetLastBuffer( EFalse ); + + if ( EBufferOne == iCurrentBuffer ) + { + iFrameBufferTwo->SetStatus( EAvailable ); + } + else + { + iFrameBufferOne->SetStatus( EAvailable ); + } + + if ( iBufferToReadExists ) // Payload has some frames not decoded + { + iStateMachine->ChangeState( ESourceDataReady ); + } + else + { + #ifdef TRACE_G729_PAYLOAD_FORMAT_READ + RDebug::Print( _L("CG729PayloadFormatRead::FillBufferL -> FillSourceBufferL") ); + #endif + + // No payload, ask for it + FillSourceBufferL(); + } + } + +// ----------------------------------------------------------------------------- +// CG729PayloadFormatRead::Streams +// Return number of audio streams for the given media. +// ----------------------------------------------------------------------------- +// +TUint CG729PayloadFormatRead::Streams(TUid aMediaType) const + { + // Need to check aMediaType for audio + if ( KUidMediaTypeAudio == aMediaType ) + { + return 1; + } + else + { + return 0; + } + } + +// ----------------------------------------------------------------------------- +// CG729PayloadFormatRead::FrameTimeInterval +// Return the frame time interval for the given media +// ----------------------------------------------------------------------------- +// +TTimeIntervalMicroSeconds CG729PayloadFormatRead::FrameTimeInterval( + TMediaId aMediaId) const + { + if ( KUidMediaTypeAudio == aMediaId.iMediaType ) + { + return iFrameTimeInterval; + } + else + { + return TTimeIntervalMicroSeconds( TInt64( 0 ) ); + } + } + +// ----------------------------------------------------------------------------- +// CG729PayloadFormatRead::Duration +// Return the frame time interval for the given media. +// NOT SUPPORTED +// ----------------------------------------------------------------------------- +// +TTimeIntervalMicroSeconds CG729PayloadFormatRead::Duration( + TMediaId /*aMediaType*/) const + { + return TTimeIntervalMicroSeconds( TInt64( 0 ) ); + } + +// ----------------------------------------------------------------------------- +// CG729PayloadFormatRead::DecodePayload +// Decodes all audio frames from the received RTP payload buffer. Decoded +// audio frames are saved to the internal array so that audio frames can be +// requested one at a time with GetNextFrame() -method. +// No assumption about frame count in RTP packet is done. +// ----------------------------------------------------------------------------- +// +void CG729PayloadFormatRead::DecodePayload( const TDesC8& aSourceBuffer ) + { + #ifdef TRACE_G729_PAYLOAD_FORMAT_READ + RDebug::Print ( _L ( "CG729PayloadFormatRead::DecodePayload - SourceBufSize: %d" ), aSourceBuffer.Length() ); + #endif + #ifdef VOIP_TRACE_ENABLED + VoipTrace( "%x %x %d", MCC_TRACE, MCC_G711_PLF_READ_DECODEPAYLOAD, + aSourceBuffer.Size() ); + #endif + + const TUint8* framePtr = aSourceBuffer.Ptr(); + TInt payloadSize( aSourceBuffer.Length() ); + const TUint8* endPtr = aSourceBuffer.Ptr() + payloadSize; + + // Calculate parameters for frame ripping + TInt frames( 0 ); + TInt frameSize( 0 ); + TInt remainder( 0 ); + iFrameIndex = 0; + + if ( !( payloadSize % (TInt) iCInfo.iFrameSize ) ) + { + // Pure audio frames + frameSize = iCInfo.iFrameSize; + frames = payloadSize / (TInt) iCInfo.iFrameSize; + remainder = 0; + + #ifdef TRACE_G729_PAYLOAD_FORMAT_READ + RDebug::Print( _L( "CG729PayloadFormatRead::DecodePayload - PURE AUDIO FRAMES: %d" ), frames ); + #endif + } + else if ( KG729CNFrameSize == payloadSize ) + { + // Payload consists of one CN frame + frameSize = KG729CNFrameSize; + frames = payloadSize / KG729CNFrameSize; + remainder = 0; + + #ifdef TRACE_G729_PAYLOAD_FORMAT_READ + RDebug::Print( _L( "CG729PayloadFormatRead::DecodePayload - ONE CNOISE FRAME: %d" ), frames ); + #endif + } + else + { + // Payload contains one CNF at the end of buffer + frameSize = iCInfo.iFrameSize; + frames = payloadSize / (TInt) iCInfo.iFrameSize; + remainder = payloadSize % (TInt) iCInfo.iFrameSize; + + #ifdef TRACE_G729_PAYLOAD_FORMAT_READ + RDebug::Print( _L( "CG729PayloadFormatRead::DecodePayload - AUDIO FRAME(s) + ONE CNOISE FRAME, FRAMES: %d, REMAINDER: %d" ), frames, remainder ); + #endif + } + + #ifdef TRACE_G729_PAYLOAD_FORMAT_READ + RDebug::Print( _L( "CG729PayloadFormatRead::DecodePayload - framesize: %d, frames: %d" ), frameSize, frames ); + #endif + + // Construct pointers to frames in payload + while ( frames-- ) + { + TPtr8 bufPtr( const_cast( framePtr ), frameSize, frameSize ); + iFrameArray.Append( bufPtr ); + + framePtr += frameSize; + + if ( framePtr >= endPtr ) + { + frames = 0; + } + } + + // Add possible comfort noise frame + if ( remainder ) + { + TPtr8 bufPtr( const_cast(framePtr), KG729CNFrameSize, KG729CNFrameSize ); + iFrameArray.Append( bufPtr ); + } + } + +// ----------------------------------------------------------------------------- +// CG729PayloadFormatRead::GetNextFrame +// Passes next audio frame decoded with DecodePayload() +// ----------------------------------------------------------------------------- +// +void CG729PayloadFormatRead::GetNextFrame( TDes8& aToBuffer ) + { + #ifdef VOIP_TRACE_ENABLED + VoipTrace( "%x %x %d", MCC_TRACE, MCC_G711_PLF_READ_GETNEXTFRAME, + iFrameArray.Count(), iFrameIndex ); + #endif + + iFrameIndex++; + + #ifdef TRACE_G729_PAYLOAD_FORMAT_READ + RDebug::Print( _L( "CG729PayloadFormatRead::GetNextFrame - FrameCount: %d, FrameIndex: %d" ), + iFrameArray.Count(), iFrameIndex ); + if ( iFrameArray.Count() ) + { + RDebug::Print( _L("CG729PayloadFormatRead::GetNextFrame SRC_LEN: %d"), + iFrameArray[iFrameIndex - 1].Length() ); + RDebug::Print( _L("CG729PayloadFormatRead::GetNextFrame SRC_MAX: %d"), + iFrameArray[iFrameIndex - 1].MaxLength() ); + } + + RDebug::Print( _L("CG729PayloadFormatRead::GetNextFrame DEST_LEN: %d"), aToBuffer.Length() ); + RDebug::Print( _L("CG729PayloadFormatRead::GetNextFrame DEST_MAX: %d"), aToBuffer.MaxLength() ); + #endif + + const TInt frmCount = iFrameArray.Count(); + + if ( iFrameIndex < frmCount ) + { + aToBuffer.Append( iFrameArray[iFrameIndex - 1] ); + iBufferToReadExists = ETrue; + } + else if ( iFrameIndex == frmCount ) + { + aToBuffer.Append( iFrameArray[iFrameIndex - 1] ); + iFrameArray.Reset(); + iBufferToReadExists = EFalse; + } + else + { + #ifdef TRACE_G729_PAYLOAD_FORMAT_READ + RDebug::Print( _L ( "CG729PayloadFormatRead::GetNextFrame FALSE" )); + #endif + iBufferToReadExists = EFalse; + } + } + +// ----------------------------------------------------------------------------- +// CG729PayloadFormatRead::DoBitUnPacking +// Does unpacking for bit-packed G729 RTP payload. +// ----------------------------------------------------------------------------- +// +TInt CG729PayloadFormatRead::DoBitUnPacking( const TDesC8& aSourceBuf, + TDes8& aDestBuf, TBool aIsCNoise ) const + { + if ( KG729CodecDecBufSize < aDestBuf.MaxLength() ) + { + #ifdef TRACE_G729_PAYLOAD_FORMAT_READ + RDebug::Print( _L("CG729PayloadFormatRead::DoBitUnPacking - DESTINATION BUF TOO SMALL!") ); + #endif + + return KErrArgument; + } + else + { + TStreamDecoder decoder; + // Initialize and take into account the header bytes + decoder.Initialize( const_cast( aSourceBuf.Ptr() ), 0, 0 ); + aDestBuf.SetLength( KG729CodecDecBufSize ); + + // Store header to temporary variables and zero the data in the + // destination buffer. After that, restore the header bytes. + TUint8 header1 = aDestBuf[0]; + TUint8 header2 = aDestBuf[1]; + aDestBuf.FillZ(); + aDestBuf[0] = header1; + aDestBuf[1] = header2; + + TUint8 numOfParams( 0 ); + if ( aIsCNoise ) + { + numOfParams = KG729NumOfCNoiseParams; + } + else + { + numOfParams = KG729NumOfAudioParams; + } + + // Don't overwrite the header bytes + TUint byteIndex( KG729NumOfHeaderBytes ); + TUint8 curParamBits( 0 ); + TUint8 decodedByte( 0 ); + for ( TInt i = 0; i < numOfParams; i++ ) + { + if ( aIsCNoise ) + { + curParamBits = KG729CodecBufCNoiseBits[i]; + } + else + { + curParamBits = KG729CodecBufAudioBits[i]; + } + + if ( curParamBits <= KBitsInByte ) + { + decodedByte = TUint8( decoder.Decode( curParamBits ) ); + aDestBuf[ byteIndex ] = decodedByte; + aDestBuf[ byteIndex + 1 ] = 0; + } + else + { + decodedByte = TUint8( decoder.Decode( curParamBits - KBitsInByte ) ); + aDestBuf[ byteIndex + 1 ] = decodedByte; + + decodedByte = TUint8( decoder.Decode( KBitsInByte ) ); + aDestBuf[ byteIndex ] = decodedByte; + } + + byteIndex += 2; + } + + return KErrNone; + } + } + +// ----------------------------------------------------------------------------- +// CG729PayloadFormatRead::ConfigurePayloadFormatL +// Configure payload decoding parameters. +// ----------------------------------------------------------------------------- +// +void CG729PayloadFormatRead::ConfigurePayloadFormatL( const TDesC8& aConfigParams ) + { + #ifdef TRACE_G729_PAYLOAD_FORMAT_READ + RDebug::Print ( _L ( "CG729PayloadFormatRead::ConfigurePayloadFormatL" ) ); + #endif + __ASSERT_ALWAYS( aConfigParams.Size() == sizeof( TMccCodecInfo ), + User::Leave( KErrArgument ) ); + + TMccCodecInfoBuffer infoBuffer; + infoBuffer.Copy( aConfigParams ); + + if ( !infoBuffer().iIsUpdate ) + { + iCInfo = infoBuffer(); + // Maximum number of frames in RTP payload + iCInfo.iHwFrameTime = KG729FrameTimeInMs; // RFC3551 + TUint pktCount = iCInfo.iMaxPtime / iCInfo.iHwFrameTime; + iCInfo.iFrameSize = KG729FrameSize10ms; + iFrameTimeInterval = TInt64( iCInfo.iHwFrameTime * TInt8( pktCount ) ); + + // Create two frame buffers used in data transfer with datapath. + // Space for two byte additional header needed by HW codec is reserved. + if ( iFrameBufferOne ) + { + delete iFrameBufferOne; + iFrameBufferOne = NULL; + } + iFrameBufferOne = CMMFDataBuffer::NewL( KG729CodecDecBufSize ); + + if ( iFrameBufferTwo ) + { + delete iFrameBufferTwo; + iFrameBufferTwo = NULL; + } + iFrameBufferTwo = CMMFDataBuffer::NewL( KG729CodecDecBufSize ); + + // PayloadBuffer contains data received from network + TInt plSize = iCInfo.iFrameSize * pktCount + KG729CNFrameSize; + + #ifdef TRACE_G729_PAYLOAD_FORMAT_READ + RDebug::Print( _L ( "CG729PayloadFormatRead::ConfigurePayloadFormatL FramesPerPacket: %d, FrameSize: %d" ), + pktCount, iCInfo.iFrameSize ); + #endif + if ( EGenRedUsed == iCInfo.iAlgoUsed ) + { + #ifdef TRACE_G729_PAYLOAD_FORMAT_READ + RDebug::Print( _L("CG729PayloadFormatRead::ConfigurePayloadFormatL, RED LEVEL: %d"), + iCInfo.iRedundancyCount ); + #endif + if ( iCInfo.iRedundancyCount ) + { + plSize *= iCInfo.iRedundancyCount; + } + + CPayloadFormatRead* redDecoder + = static_cast( iClip ); + + TMccRedPayloadReadConfig config; + config.iRedBlockCount = iCInfo.iRedundancyCount; + config.iMaxPayloadSize = iCInfo.iFrameSize * pktCount; + config.iNumOfEncodings = 1; + config.iRedPayloadType = iCInfo.iRedundantPayload; + config.InitPayloadTypes(); + config.iEncPayloadTypes[0] = iCInfo.iPayloadType; + TMccRedPayloadReadPckg pckg( config ); + redDecoder->ConfigurePayloadFormatL( pckg ); + } + + if ( iSourceBuffer && iSourceBufOwnership ) + { + delete iSourceBuffer; + iSourceBuffer = NULL; + iSourceBufOwnership = EFalse; + } + iSourceBuffer = CreateClipBufferL( plSize, iSourceBufOwnership ); + } + else + { + UpdateConfigurationL( infoBuffer() ); + } + + #ifdef TRACE_G729_PAYLOAD_FORMAT_READ + RDebug::Print ( _L ( "CG729PayloadFormatRead::ConfigurePayloadFormatL() OUT" ) ); + #endif + } + +// ----------------------------------------------------------------------------- +// CG729PayloadFormatRead::UpdateConfigurationL +// Update payload decoder parameters +// ----------------------------------------------------------------------------- +// +void CG729PayloadFormatRead::UpdateConfigurationL( TMccCodecInfo& aCodecInfo ) + { + #ifdef TRACE_G729_PAYLOAD_FORMAT_READ + RDebug::Print( _L("CG729PayloadFormatRead::UpdateConfigurationL IN") ); + #endif + + if ( iCInfo.iMaxPtime != aCodecInfo.iMaxPtime ) + { + // Maximum number of frames in RTP payload + const TUint pktCount = aCodecInfo.iMaxPtime / iCInfo.iHwFrameTime; + iFrameTimeInterval = TInt64( iCInfo.iHwFrameTime * TInt8( pktCount ) ); + + // PayloadBuffer contains data received from network + if ( iSourceBufOwnership ) + { + delete iSourceBuffer; + iSourceBufOwnership = EFalse; + } + iSourceBuffer = NULL; + + TInt plSize = iCInfo.iFrameSize * pktCount + KG729CNFrameSize; + + iSourceBuffer = CreateClipBufferL( plSize, iSourceBufOwnership ); + + iCInfo.iMaxPtime = aCodecInfo.iMaxPtime; + } + + #ifdef TRACE_G729_PAYLOAD_FORMAT_READ + RDebug::Print( _L("CG729PayloadFormatRead::UpdateConfigurationL OUT") ); + #endif + } + +// ----------------------------------------------------------------------------- +// CG729PayloadFormatRead::CreateClipBufferL +// Creates buffer needed in data transfer with format readers clip. +// ----------------------------------------------------------------------------- +// +CMMFDataBuffer* CG729PayloadFormatRead::CreateClipBufferL( + TUint aSize, TBool& aIsOwnBuffer ) + { + #ifdef TRACE_G729_PAYLOAD_FORMAT_READ + RDebug::Print( _L("CG729PayloadFormatRead::CreateClipBufferL" ) ); + #endif + + CMMFDataBuffer* buffer( NULL ); + + if ( iClip->CanCreateSourceBuffer() ) + { + static_cast( iClip )->SuggestSourceBufferSize( aSize ); + + TBool reference( EFalse ); + CMMFBuffer* sourceBuf + = iClip->CreateSourceBufferL( KUidMediaTypeAudio, reference ); + TBool isSupportedBuf + = CMMFBuffer::IsSupportedDataBuffer( sourceBuf->Type() ); + TBool isOwnBuffer = reference ? EFalse : ETrue; + + if ( !isSupportedBuf ) + { + if ( isOwnBuffer ) + { + delete sourceBuf; + } + + User::Leave( KErrNotSupported ); + } + + aIsOwnBuffer = isOwnBuffer; + buffer = static_cast( sourceBuf ); + } + else + { + aIsOwnBuffer = ETrue; + buffer = CMMFDataBuffer::NewL( aSize ); + } + + return buffer; + } + +// ========================== OTHER EXPORTED FUNCTIONS ========================= + +// End of File