diff -r 000000000000 -r 1bce908db942 multimediacommscontroller/mmccamrpayloadformat/src/amrpayloadformatread.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/multimediacommscontroller/mmccamrpayloadformat/src/amrpayloadformatread.cpp Tue Feb 02 01:04:58 2010 +0200 @@ -0,0 +1,1173 @@ +/* +* 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 +* AMR audio. +* +*/ + + + + +// INCLUDE FILES +#include +#include +#include "amrpayloadformatread.h" +#include "amrpayloadencoder.h" +#include "amrpayloaddecoder.h" +#include "amrpayloaddecoderoa.h" +#include "amrpayloadformatutil.h" +#include "amrcommonutil.h" +#include "mccrtpdatasource.h" +#include "mccuids.hrh" +#include "mccinternaldef.h" +#include "amrpayloadformatter.h" +#include "mccredpayloadread.h" + +#ifdef VOIP_TRACE_ENABLED +#include +#endif + +// CONSTANTS +const TReal KTimeMultiplier = 0.001; + +// ============================= LOCAL FUNCTIONS =============================== + +// ============================ MEMBER FUNCTIONS =============================== + +// ----------------------------------------------------------------------------- +// CAmrPayloadFormatRead::CAmrPayloadFormatRead +// C++ default constructor can NOT contain any code, that +// might leave. +// ----------------------------------------------------------------------------- +// +CAmrPayloadFormatRead::CAmrPayloadFormatRead ( ) : + iIsNb( ETrue ), iSamplingRate( KAmrNbSampleRate ), iChannels( 1 ), + iMode( EAmrFrame12_2 ), iCmr ( EAmrModeReq7 ), iStreamEncoder( TStreamEncoder() ) + { + } + +// ----------------------------------------------------------------------------- +// CAmrPayloadFormatRead::ConstructL +// Symbian 2nd phase constructor can leave. +// ----------------------------------------------------------------------------- +// +void CAmrPayloadFormatRead::ConstructL ( MDataSource* aSource ) + { + User::LeaveIfNull( aSource ); + + iRtpDataSource = aSource; + iClip = aSource; + iBufferToReadExists = EFalse; + + iFourCC.Set( TFourCC( ' ','A','M','R' ) ); + + // Set default value of iChannels and iFramesPerPacket + iFramesPerPacket = 1; + iChannels = 1; + + // Initialize decoding state machine + iStateMachine = CFormatDecodeStateMachine::NewL( this ); + iStateMachine->ChangeState( EDecodeIdle ); + + iCurrentBuffer = EBufferOne; + + #ifdef FTD_ENABLED + + User::LeaveIfError( iJBufStatsQueue.OpenGlobal( KMccJBufferStats, + EOwnerProcess ) ); + + #endif + } + +// ----------------------------------------------------------------------------- +// CAmrPayloadFormatRead::NewL +// +// Two-phased constructor. +// ----------------------------------------------------------------------------- +// +CAmrPayloadFormatRead* CAmrPayloadFormatRead::NewL ( MDataSource* aSource ) + { + __ASSERT_ALWAYS( aSource, User::Leave( KErrArgument ) ); + + AMR_PAYLOAD_FORMAT_READ ( "CAmrPayloadFormatRead::NewL" ); + + CAmrPayloadFormatRead* self = new ( ELeave ) CAmrPayloadFormatRead; + CleanupStack::PushL ( self ); + self->ConstructL ( aSource ); + CleanupStack::Pop( self ); + return self; + } + +// ----------------------------------------------------------------------------- +// CAmrPayloadFormatRead::~CAmrPayloadFormatRead +// +// Destructor. +// ----------------------------------------------------------------------------- +// +CAmrPayloadFormatRead::~CAmrPayloadFormatRead ( ) + { + // commented out CreateSourceBufferL now sets aReference to ETrue. + // datapath doesn't clean this buffer any longer. + #ifdef TRACE_AMR_PAYLOAD_FORMAT_READ + AMR_PAYLOAD_FORMAT_READ2 ( "CAmrPayloadFormatRead::~CAmrPayloadFormatRead: 0x%x", this ); + AMR_PAYLOAD_FORMAT_READ2 ( "CAmrPayloadFormatRead::~CAmrPayloadFormatRead iFrameBufferOne: 0x%x", iFrameBufferOne ); + AMR_PAYLOAD_FORMAT_READ2 ( "CAmrPayloadFormatRead::~CAmrPayloadFormatRead iFrameBufferTwo: 0x%x", iFrameBufferTwo ); + AMR_PAYLOAD_FORMAT_READ2 ( "CAmrPayloadFormatRead::~CAmrPayloadFormatRead iSourceBuffer: 0x%x", iSourceBuffer ); + AMR_PAYLOAD_FORMAT_READ2 ( "CAmrPayloadFormatRead::~CAmrPayloadFormatRead iStateMachine: 0x%x", iStateMachine ); + AMR_PAYLOAD_FORMAT_READ2 ( "CAmrPayloadFormatRead::~CAmrPayloadFormatRead iPayloadDecoder: 0x%x", iPayloadDecoder ); + AMR_PAYLOAD_FORMAT_READ2 ( "CAmrPayloadFormatRead::~CAmrPayloadFormatRead iRtpDataSource: 0x%x", iRtpDataSource ); + AMR_PAYLOAD_FORMAT_READ2 ( "CAmrPayloadFormatRead::~CAmrPayloadFormatRead iClip: 0x%x", iClip ); + AMR_PAYLOAD_FORMAT_READ2 ( "CAmrPayloadFormatRead::~CAmrPayloadFormatRead iDataPath: 0x%x", iDataPath ); + AMR_PAYLOAD_FORMAT_READ2 ( "CAmrPayloadFormatRead::~CAmrPayloadFormatRead iBufferToRead: 0x%x", iBufferToRead ); + #endif + + + delete iFrameBufferOne; + delete iFrameBufferTwo; + if ( iSourceBufOwnership ) + { + delete iSourceBuffer; + } + iSourceBuffer = NULL; + + if ( iStateMachine ) + { + iStateMachine->Cancel( ); + delete iStateMachine; + } + + delete iPayloadDecoder; + iRtpDataSource = NULL; + iClip = NULL; + iDataPath = NULL; + iBufferToRead = NULL; + iEventHandler = NULL; + + #ifdef FTD_ENABLED + iJBufStatsQueue.Close(); + #endif + } + +// ----------------------------------------------------------------------------- +// CAmrPayloadFormatRead::Streams +// Return number of audio streams for the given media +// ----------------------------------------------------------------------------- +// +TUint CAmrPayloadFormatRead::Streams( TUid aMediaType ) const + { + if ( KUidMediaTypeAudio == aMediaType ) + { + return 1; + } + else + { + return 0; + } + } + +// ----------------------------------------------------------------------------- +// CAmrPayloadFormatRead::FrameTimeInterval +// Return the frame time interval for the given media +// ----------------------------------------------------------------------------- +// +TTimeIntervalMicroSeconds CAmrPayloadFormatRead::FrameTimeInterval( + TMediaId aMediaId ) const + { + if ( KUidMediaTypeAudio == aMediaId.iMediaType ) + { + TInt hwFrametime = static_cast( iCInfo.iHwFrameTime ); + return TTimeIntervalMicroSeconds( TInt64( hwFrametime ) ); + } + else + { + return TTimeIntervalMicroSeconds( TInt64( 0 ) ); + } + } + +// ----------------------------------------------------------------------------- +// CAmrPayloadFormatRead::FillBufferL +// Fill Buffer +// ----------------------------------------------------------------------------- +// +void CAmrPayloadFormatRead::FillBufferL( CMMFBuffer* aBuffer, + MDataSink* aConsumer, TMediaId aMediaId ) + { + #ifdef TRACE_AMR_PAYLOAD_FORMAT_READ + AMR_PAYLOAD_FORMAT_READ ( "CAmrPayloadFormatRead::FillBufferL( )" ); + #endif + + User::LeaveIfNull( aBuffer ); + User::LeaveIfNull( aConsumer ); + + #ifdef TRACE_AMR_PAYLOAD_FORMAT_READ + AMR_PAYLOAD_FORMAT_READ3 ( "CAmrPayloadFormatRead::FillBufferL( ) buffer 0x%x passed in with length %d bytes \n", aBuffer, aBuffer->BufferSize( ) ); + #endif + #ifdef VOIP_TRACE_ENABLED + VoipTrace( "%x %x %x %x", MCC_TRACE, MCC_AMR_PLF_READ_FILLBUFFERL, + aBuffer, aConsumer ); + #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 AmrPayloadFormatRead owns + aBuffer->SetLastBuffer( EFalse ); + + iFillRequested = ETrue; + + if ( iCurrentBuffer == EBufferOne ) + { + iFrameBufferTwo->SetStatus( EAvailable ); + } + else + { + iFrameBufferOne->SetStatus( EAvailable ); + } + + if ( iBufferToReadExists ) // Payload has some frames not decoded + { + iStateMachine->ChangeState( ESourceDataReady ); + } + else + { + #ifdef TRACE_AMR_PAYLOAD_FORMAT_READ + AMR_PAYLOAD_FORMAT_READ ( "CAmrPayloadFormatRead::FillBufferL( ), Request data from source\n" ); + #endif + + FillSourceBufferL(); // No payload ask for it + } + } + +// ----------------------------------------------------------------------------- +// CAmrPayloadFormatRead::DoRead +// Reads data starting from the given position into the source buffer +// ----------------------------------------------------------------------------- +// +TBool CAmrPayloadFormatRead::DoRead( CMMFBuffer* aBuffer ) + { + #ifdef TRACE_AMR_PAYLOAD_FORMAT_READ + AMR_PAYLOAD_FORMAT_READ ( "CAmrPayloadFormatRead::DoRead" ); + #endif + #ifdef VOIP_MCC_DL_TRACE_ENABLED + VoipTrace( "%x %x %x", MCC_TRACE, MCC_AMR_PLF_READ_DOREAD, aBuffer ); + #endif + + if ( !aBuffer ) + { + return EFalse; + } + + if ( EFull == aBuffer->Status( ) ) + { + #ifdef TRACE_AMR_PAYLOAD_FORMAT_READ + RDebug::Print ( _L ( "CAmrPayloadFormatRead::DoRead - Buffer already full" ) ); + #endif + + return EFalse; + } + + if ( iNumOfFrames == 0 ) + { + return EFalse; + } + + TAmrFrame* frames = iPayloadDecoder->Frames( ); + TDes8& bufferDes = static_cast( aBuffer )->Data(); + TInt byteIndex = bufferDes.Length( ); + + TUint8* desPtr = const_cast( bufferDes.Ptr( ) ); + iStreamEncoder.Initialize( desPtr, byteIndex, 0 ); + + #ifdef TRACE_AMR_PAYLOAD_FORMAT_READ + AMR_PAYLOAD_FORMAT_READ2 ( "CAmrPayloadFormatRead::DoRead - iCurrentFrame = %d", + iCurrentFrame ); + #endif + + TInt bitCount = iPayloadDecoder->SpeechBitCount( frames[iCurrentFrame].iFrameType ); + // Calculate byte count + TInt nextFrameLen = + bitCount % TInt(KNumValue8) == 0 ? bitCount / TInt(KNumValue8) : bitCount / TInt(KNumValue8) + 1; + + #ifdef TRACE_AMR_PAYLOAD_FORMAT_READ + AMR_PAYLOAD_FORMAT_READ4 ( "CAmrPayloadFormatRead::DoRead - iCurrentFrame = %d iNumOfFrames = %d byteIndex = %d", + iCurrentFrame, iNumOfFrames, byteIndex ); + #endif + + // Construct 8-bit frame header. + // +-+-+-+-+-+-+-+-+ + // |P| FT |Q|P|P| + // +-+-+-+-+-+-+-+-+ + iStreamEncoder.Encode( 0, 1 ); + iStreamEncoder.Encode( TInt( frames[iCurrentFrame].iFrameType ), KNumValue4 ); + iStreamEncoder.Encode( frames[iCurrentFrame].iFrameQualityInd, 1 ); + iStreamEncoder.Encode( 0, KNumValue2 ); + + if ( bitCount > 0 ) + { + // Construct core frame part ( speech data ) + iStreamEncoder.Encode( frames[iCurrentFrame].iFrameData, 0, + frames[iCurrentFrame].iBitIndex, bitCount ); + if ( iStreamEncoder.BitIndex( ) != 0 ) + { + // Need padding to byte boundray + iStreamEncoder.Encode( 0, KNumValue8 - iStreamEncoder.BitIndex( ) ); + } + } + + // Update iCurrentFrame + iCurrentFrame++; + + byteIndex = byteIndex + nextFrameLen + 1; // Add 1 for frame header byte + + // Get next frame length + if ( iCurrentFrame < iNumOfFrames ) + { + bitCount = iPayloadDecoder->SpeechBitCount( frames[iCurrentFrame].iFrameType ); + // Calculate byte count + nextFrameLen = + bitCount % (TInt) KNumValue8 == 0 ? bitCount / (TInt) KNumValue8 : bitCount / (TInt) KNumValue8 + 1; + } + + bufferDes.SetLength( byteIndex ); + + #ifdef TRACE_AMR_PAYLOAD_FORMAT_READ + AMR_PAYLOAD_FORMAT_READ4 ( "CAmrPayloadFormatRead::DoRead - after decoding iCurrentFrame = %d iNumOfFrames = %d byteIndex = %d", + iCurrentFrame, iNumOfFrames, byteIndex ); + #endif + + if ( iCurrentFrame == iNumOfFrames ) + { + // Packet is fully decoded. + // If it is the last buffer from RtpSourceSink, then we are not + // expecting more packets. Also SetLastBuffer to notify datapath. + if( iBufferToRead->LastBuffer( ) ) + { + aBuffer->SetLastBuffer( ETrue ); + aBuffer->SetStatus( EFull ); + } + return ETrue; + } + + return EFalse; + } + +// ----------------------------------------------------------------------------- +// CAmrPayloadFormatRead::FillSinkBufferL +// Read RTP payload and convert it into AMR frames. +// ----------------------------------------------------------------------------- +// +void CAmrPayloadFormatRead::FillSinkBufferL( ) + { + #ifdef TRACE_AMR_PAYLOAD_FORMAT_READ + AMR_PAYLOAD_FORMAT_READ ( "CAmrPayloadFormatRead::FillSinkBuffer( )" ); + #endif + #ifdef VOIP_MCC_DL_TRACE_ENABLED + VoipTrace( "%x %x", MCC_TRACE, MCC_AMR_PLF_READ_FILLSINKBUFFER ); + #endif + + CMMFBuffer* curBuffer; + if ( EBufferOne == iCurrentBuffer ) + { + curBuffer = iFrameBufferOne; + + #ifdef TRACE_AMR_PAYLOAD_FORMAT_READ + AMR_PAYLOAD_FORMAT_READ ( "CAmrPayloadFormatRead::FillSinkBuffer( ) - Current Buffer One" ); + #endif + } + else + { + curBuffer = iFrameBufferTwo; + + #ifdef TRACE_AMR_PAYLOAD_FORMAT_READ + AMR_PAYLOAD_FORMAT_READ ( "CAmrPayloadFormatRead::FillSinkBuffer( ) - Current Buffer Two" ); + #endif + } + + curBuffer->SetStatus( EAvailable ); + TBool allFrmBuffered = DoRead( curBuffer ); + curBuffer->SetFrameNumber( + iRecvHeader.iTimestamp + ( ( iCurrentFrame - 1 ) + * TUint( iCInfo.iHwFrameTime * iSamplingRate * KTimeMultiplier ) ) ); + + #ifdef TRACE_AMR_PAYLOAD_FORMAT_READ + AMR_PAYLOAD_FORMAT_READ2 ( "CAmrPayloadFormatRead::FillSinkBuffer - FRAMENUM: %u", + curBuffer->FrameNumber() ); + #endif + + // Do not wait for the buffer to be filled up. If we do, this will cause jitters in + // comfort-noise ( SID frame ) playing since SID-frame packets take considerably less + // data bytes and it will delay waiting for many SID-frame packets before forwarding them to + // DataPath for further play-out processing. + // Instead, forward the data as soon as we receive and decode one packet + // to avoid jitters in play-out. + if ( allFrmBuffered ) + { + iBufferToReadExists = EFalse; + } + + + // Do not forward zero length buffers + if ( curBuffer->BufferSize() > 0 ) + { + iStateMachine->ChangeState( EEmptyDataToSink ); + } + else + { + #ifdef TRACE_AMR_PAYLOAD_FORMAT_READ + AMR_PAYLOAD_FORMAT_READ ( "CAmrPayloadFormatRead::FillSinkBufferL( ), Request data from source\n" ); + #endif + + FillSourceBufferL(); // No payload ask for it + } + + #ifdef TRACE_AMR_PAYLOAD_FORMAT_READ + AMR_PAYLOAD_FORMAT_READ ( "CAmrPayloadFormatRead::FillSinkBuffer - DONE" ); + #endif + } + +// ----------------------------------------------------------------------------- +// CAmrPayloadFormatRead::FillSourceBufferL +// Send fill buffer request to RTP Data Source +// ----------------------------------------------------------------------------- +// +void CAmrPayloadFormatRead::FillSourceBufferL( ) + { + #ifdef TRACE_AMR_PAYLOAD_FORMAT_READ + AMR_PAYLOAD_FORMAT_READ ( "CAmrPayloadFormatRead::FillSourceBufferL( )" ); + #endif + + iClip->FillBufferL(iSourceBuffer, this, iMediaId ); + } + +// ----------------------------------------------------------------------------- +// CAmrPayloadFormatRead::SendDataToSinkL +// Send full frame buffer to Data Path +// ----------------------------------------------------------------------------- +// +void CAmrPayloadFormatRead::SendDataToSinkL( ) + { + #ifdef VOIP_MCC_DL_TRACE_ENABLED + VoipTrace( "%x %x", MCC_TRACE, MCC_AMR_PLF_READ_SENDDATATOSINKL ); + #endif + + iFillRequested = EFalse; + + if ( EBufferOne == iCurrentBuffer ) + { + #ifdef TRACE_AMR_PAYLOAD_FORMAT_READ + AMR_PAYLOAD_FORMAT_READ ( "CAmrPayloadFormatRead::SendDataToSinkL( ) - BufferOne" ); + #endif + + iDataPath->BufferFilledL( iFrameBufferOne ); + iCurrentBuffer = EBufferTwo; + if ( iBufferToReadExists && !iFrameBufferOne->LastBuffer( ) ) + { + // More payload buffer is needed + iStateMachine->ChangeState( ESourceDataReady ); + } + } + else + { + #ifdef TRACE_AMR_PAYLOAD_FORMAT_READ + AMR_PAYLOAD_FORMAT_READ ( "CAmrPayloadFormatRead::SendDataToSinkL( ) - BufferTwo" ); + #endif + + iDataPath->BufferFilledL( iFrameBufferTwo ); + iCurrentBuffer = EBufferOne; + if ( iBufferToReadExists && !iFrameBufferTwo->LastBuffer( ) ) + { + // More payload buffer is needed + iStateMachine->ChangeState( ESourceDataReady ); + } + } + + #ifdef TRACE_AMR_PAYLOAD_FORMAT_READ + AMR_PAYLOAD_FORMAT_READ ( "CAmrPayloadFormatRead::SendDataToSinkL( ) - DONE" ); + #endif + } + +// ----------------------------------------------------------------------------- +// CAmrPayloadFormatRead::CreateSourceBufferL +// Create a source buffer for the given media and indicate in aReference if +// buffer is created. +// ----------------------------------------------------------------------------- +// +CMMFBuffer* CAmrPayloadFormatRead::CreateSourceBufferL( TMediaId aMediaId, + TBool &aReference ) + { + #ifdef VOIP_TRACE_ENABLED + VoipTrace( "%x %x", MCC_TRACE, MCC_AMR_PLF_READ_CREATESOURCEBUFFERL ); + #endif + + if ( KUidMediaTypeAudio != aMediaId.iMediaType ) + { + User::Leave( KErrNotSupported ); + } + + // the source buffers belong to AmrPayloadFormatRead not to datapath + // aference should be set to ETrue and destried by AmrPayloadFormatRead itself. + aReference = ETrue; + return iFrameBufferOne; + } + +// ----------------------------------------------------------------------------- +// CAmrPayloadFormatRead::CreateSourceBufferL +// Create a source buffer for the given media, setting frame size to match +// the given sink buffer +// ----------------------------------------------------------------------------- +// +CMMFBuffer* CAmrPayloadFormatRead::CreateSourceBufferL( TMediaId aMediaId, + CMMFBuffer& /*aSinkBuffer*/, TBool &aReference ) + { + #ifdef VOIP_TRACE_ENABLED + VoipTrace( "%x %x", MCC_TRACE, MCC_AMR_PLF_READ_CREATESOURCEBUFFERL ); + #endif + + if ( KUidMediaTypeAudio != aMediaId.iMediaType ) + { + User::Leave( KErrNotSupported ); + } + + return CreateSourceBufferL( aMediaId, aReference ); + } + +// ----------------------------------------------------------------------------- +// CAmrPayloadFormatRead::SourceDataTypeCode +// Return the source data type ( four CC code ) for the given media +// ----------------------------------------------------------------------------- +// +TFourCC CAmrPayloadFormatRead::SourceDataTypeCode( TMediaId aMediaId ) + { + if ( KUidMediaTypeAudio == aMediaId.iMediaType ) + { + #ifdef TRACE_AMR_PAYLOAD_FORMAT_READ + AMR_PAYLOAD_FORMAT_READ2( + "CAmrPayloadFormatRead::SourceDataTypeCode: 0x%x", iFourCC.FourCC() ); + #endif + return iFourCC; + } + else + { + return TFourCC( ); //defaults to 'NULL' fourCC + } + } + +// ----------------------------------------------------------------------------- +// CAmrPayloadFormatRead::SetSourceDataTypeCode +// Set the source data type to the given four CC code for the given media +// ----------------------------------------------------------------------------- +// +TInt CAmrPayloadFormatRead::SetSourceDataTypeCode( TFourCC aSourceFourCC, + TMediaId aMediaId ) + { + #ifdef TRACE_AMR_PAYLOAD_FORMAT_READ + AMR_PAYLOAD_FORMAT_READ2( + "CAmrPayloadFormatRead::SetSourceDataTypeCode: 0x%x", + aSourceFourCC.FourCC() ); + #endif + #ifdef VOIP_TRACE_ENABLED + VoipTrace( "%x %x %d", MCC_TRACE, MCC_AMR_PLF_READ_SETSOURCEDATATYPECODE, + aSourceFourCC.FourCC() ); + #endif + + if ( KUidMediaTypeAudio != aMediaId.iMediaType ) + { + return KErrNotSupported; + } + + iFourCC = aSourceFourCC; + iMediaId = aMediaId; + + if ( aSourceFourCC == KMccFourCCIdAMRWB ) + { + // Nb is set true in the constructor by default. + iIsNb = EFalse; + SetSampleRate( KAmrWbSampleRate ); + } + + iClip->SetSourceDataTypeCode( iFourCC, iMediaId ); + + return KErrNone; + } + +// ----------------------------------------------------------------------------- +// CAmrPayloadFormatRead::SourceThreadLogon +// Log in to the source thread +// ----------------------------------------------------------------------------- +// +TInt CAmrPayloadFormatRead::SourceThreadLogon( + MAsyncEventHandler& aEventHandler ) + { + #ifdef VOIP_TRACE_ENABLED + VoipTrace( "%x %x", MCC_TRACE, MCC_AMR_PLF_READ_SOURCETHREADLOGON ); + #endif + + iEventHandler = &aEventHandler; + iClip->SourceThreadLogon( aEventHandler ); + return KErrNone; + } + +// ----------------------------------------------------------------------------- +// CAmrPayloadFormatRead::NegotiateSourceL( MDataSink& aDataSink ) +// Negotiate source settings to match data sink object. +// Re-size frame buffers if needed +// ----------------------------------------------------------------------------- +// +void CAmrPayloadFormatRead::NegotiateSourceL( MDataSink& /*aDataSink*/ ) + { + #ifdef VOIP_TRACE_ENABLED + VoipTrace( "%x %x", MCC_TRACE, MCC_AMR_PLF_READ_NEGOTIATESOURCEL ); + #endif + + iClip->NegotiateSourceL( *this ); + } + +// ----------------------------------------------------------------------------- +// CAmrPayloadFormatRead::SourceThreadLogoff +// Log out of the source thread. +// ----------------------------------------------------------------------------- +// +void CAmrPayloadFormatRead::SourceThreadLogoff( ) + { + #ifdef VOIP_TRACE_ENABLED + VoipTrace( "%x %x", MCC_TRACE, MCC_AMR_PLF_READ_SOURCETHREADLOGOFF ); + #endif + + iClip->SourceThreadLogoff( ); + } + +// ----------------------------------------------------------------------------- +// CAmrPayloadFormatRead::DataBufferFilledL +// Called after the data buffer is filled. Update the number of bytes read +// and the current read position for the next read operation. +// ----------------------------------------------------------------------------- +// +void CAmrPayloadFormatRead::DataBufferFilledL( CMMFBuffer* aBuffer, + const TRtpRecvHeader& aRtpHeader ) + { + AMR_PAYLOAD_FORMAT_READ2( "CAmrPayloadFormatRead::DataBufferFilledL TSTAMP: %u", + aRtpHeader.iTimestamp ) + + __ASSERT_ALWAYS( aBuffer, User::Leave( KErrArgument ) ); + __ASSERT_ALWAYS( KUidMmfDataBuffer == aBuffer->Type(), + User::Leave( KErrNotSupported) ); + __ASSERT_ALWAYS( iSourceBuffer == aBuffer, User::Leave( KErrArgument ) ); + + AMR_PAYLOAD_FORMAT_READ2( "CAmrPayloadFormatRead::DataBufferFilledL LEN:%d", + iSourceBuffer->Data().Length() ) + + if ( !iSourceBuffer->Data().Size() ) + { + AMR_PAYLOAD_FORMAT_READ( "CAmrPayloadFormatRead::BufferFilledL NO DATA" ) + + // Request for a new buffer or playback is stopped + FillSourceBufferL(); + return; + } + + iBufferToRead = iSourceBuffer; + iRecvHeader = aRtpHeader; + iBufferToReadExists = ETrue; + + // Get a reference to the data + TDes8& srcData = iSourceBuffer->Data(); + + iPayloadDecoder->SetPayloadBuffer( srcData ); + iPayloadDecoder->SetChannelCount( iChannels ); + iPayloadDecoder->SetFrameBlockCount( iFramesPerPacket ); + + // Decoder rips off redundant frames already received and increases + // timestamp accordingly. This prevents frame placing too early at + // jitter buffer's playout buffer. + const TUint32 timeStampIncrement = + TUint32( iCInfo.iHwFrameTime * iChannels * iSamplingRate * KTimeMultiplier ); + + iNumOfFrames = iPayloadDecoder->DecodePayload( iRecvHeader.iTimestamp, + timeStampIncrement ); + + iBufferToRead->SetFrameNumber( iRecvHeader.iTimestamp ); + + // If the mode request has changed and it is a speech mode, then report + // it to subcontroller. Otherwise it can be ignored (RFC3267 4.3.1) + const TAmrModeRequest updateCmr = iPayloadDecoder->ModeRequest(); + if ( updateCmr != iCmr && updateCmr != EAmrModeReqNone ) + { + AMR_PAYLOAD_FORMAT_READ( "CAmrPayloadFormatRead::BufferFilledL MODE CHANGE" ) + + iCmr = updateCmr; + SendAmrEventToClient( EMccInternalAmrEventCmr ); + } + + AMR_PAYLOAD_FORMAT_READ2( "CAmrPayloadFormatRead::BufferFilledL MODE_REQ: %u", updateCmr ) + + // Read frame data and forward it to data sink + iCurrentFrame = 0; + + // Whenever BufferFilledL is called from RtpSourceSink + // Set the state machine to fill sinkbuffer + if ( iNumOfFrames ) + { + iStateMachine->ChangeState( ESourceDataReady ); + } + else + { + AMR_PAYLOAD_FORMAT_READ( "CAmrPayloadFormatRead::BufferFilledL NO ACCEPTED FRAMES" ) + + // Request for a new buffer or playback is stopped + FillSourceBufferL(); + } + } + +// ----------------------------------------------------------------------------- +// CAmrPayloadFormatRead::NumChannels +// Gets the number of channels +// ----------------------------------------------------------------------------- +// +TUint CAmrPayloadFormatRead::NumChannels( ) + { + return KMono; + } + +// ----------------------------------------------------------------------------- +// CAmrPayloadFormatRead::SampleRate +// Returns the samplerate +// ----------------------------------------------------------------------------- +// +TUint CAmrPayloadFormatRead::SampleRate( ) + { + return iSamplingRate; + } + +// ----------------------------------------------------------------------------- +// CAmrPayloadFormatRead::SetSampleRate +// Only supported sample rate for AMR-NB is 8000Hz +// ----------------------------------------------------------------------------- +// +TInt CAmrPayloadFormatRead::SetSampleRate ( TUint aSampleRate ) + { + #ifdef VOIP_TRACE_ENABLED + VoipTrace( "%x %x %d", MCC_TRACE, MCC_AMR_PLF_READ_SETSAMPLERATE, + aSampleRate ); + #endif + + if( (iIsNb && KAmrNbSampleRate != aSampleRate) || + (!iIsNb && KAmrWbSampleRate != aSampleRate) ) + { + return KErrNotSupported; + } + else + { + iSamplingRate = aSampleRate; + return KErrNone; + } + } + +// ----------------------------------------------------------------------------- +// CAmrPayloadFormatRead::Duration +// Return the clip duration for the given media. +// ----------------------------------------------------------------------------- +// +TTimeIntervalMicroSeconds CAmrPayloadFormatRead::Duration( TMediaId /*aMediaType*/ ) const + { + return TTimeIntervalMicroSeconds( TInt64( 0 ) ); + } + +// ----------------------------------------------------------------------------- +// CAmrPayloadFormatRead::CancelDlRequest( ) +// Cancels the statemachine and resets the buffers +// ----------------------------------------------------------------------------- +// +void CAmrPayloadFormatRead::CancelDlRequest() + { + #ifdef TRACE_AMR_PAYLOAD_FORMAT_READ + AMR_PAYLOAD_FORMAT_READ( "CAmrPayloadFormatRead::CancelDlRequest" ); + #endif + + iStateMachine->Cancel(); + iStateMachine->ChangeState( EDecodeIdle ); + + if ( iFrameBufferOne && iFrameBufferTwo ) + { + iFrameBufferOne->SetLastBuffer( EFalse ); + iFrameBufferTwo->SetLastBuffer( EFalse ); + + iFrameBufferOne->SetStatus( EAvailable ); + iFrameBufferTwo->SetStatus( EAvailable ); + } + + iBufferToReadExists = EFalse; + iCurrentBuffer = EBufferOne; + iFillRequested = EFalse; + } + +// ----------------------------------------------------------------------------- +// CAmrPayloadFormatRead::SourcePrimeL() +// +// ----------------------------------------------------------------------------- +// +void CAmrPayloadFormatRead::SourcePrimeL() + { + #ifdef TRACE_AMR_PAYLOAD_FORMAT_READ + AMR_PAYLOAD_FORMAT_READ( "CAmrPayloadFormatRead::SourcePrimeL" ); + #endif + #ifdef VOIP_TRACE_ENABLED + VoipTrace( "%x %x", MCC_TRACE, MCC_AMR_PLF_READ_SOURCEPRIMEL ); + #endif + + iClip->SourcePrimeL(); + } + +// ----------------------------------------------------------------------------- +// CAmrPayloadFormatRead::SourcePlayL() +// Starts the source +// ----------------------------------------------------------------------------- +// +void CAmrPayloadFormatRead::SourcePlayL() + { + #ifdef TRACE_AMR_PAYLOAD_FORMAT_READ + AMR_PAYLOAD_FORMAT_READ( "CAmrPayloadFormatRead::SourcePlayL" ); + #endif + #ifdef VOIP_TRACE_ENABLED + VoipTrace( "%x %x", MCC_TRACE, MCC_AMR_PLF_READ_SOURCEPLAYL ); + #endif + + #ifdef FTD_ENABLED + iLatestSeqNum = 0; + iTotalFrames = 0; + iLostFrames = 0; + #endif + + // Initialize payload decoder + iPayloadDecoder->Initialize(); + + iClip->SourcePlayL(); + } + +// ----------------------------------------------------------------------------- +// CAmrPayloadFormatRead::SourcePauseL() +// Pauses the source +// ----------------------------------------------------------------------------- +// +void CAmrPayloadFormatRead::SourcePauseL() + { + #ifdef TRACE_AMR_PAYLOAD_FORMAT_READ + AMR_PAYLOAD_FORMAT_READ( "CAmrPayloadFormatRead::SourcePauseL" ); + #endif + #ifdef VOIP_TRACE_ENABLED + VoipTrace( "%x %x", MCC_TRACE, MCC_AMR_PLF_READ_SOURCEPAUSEL ); + #endif + + this->CancelDlRequest(); + iClip->SourcePauseL(); + } + +// ----------------------------------------------------------------------------- +// CAmrPayloadFormatRead::SourceStopL( ) +// Stops the source +// ----------------------------------------------------------------------------- +// +void CAmrPayloadFormatRead::SourceStopL() + { + #ifdef TRACE_AMR_PAYLOAD_FORMAT_READ + AMR_PAYLOAD_FORMAT_READ( "CAmrPayloadFormatRead::SourceStopL" ); + #endif + #ifdef VOIP_TRACE_ENABLED + VoipTrace( "%x %x", MCC_TRACE, MCC_AMR_PLF_READ_SOURCESTOPL ); + #endif + + this->CancelDlRequest(); + iClip->SourceStopL(); + } + +// ----------------------------------------------------------------------------- +// CAmrPayloadFormatRead::SinkDataTypeCode() +// Returns the datatype code for this Format Decoder +// ----------------------------------------------------------------------------- +// +TFourCC CAmrPayloadFormatRead::SinkDataTypeCode( TMediaId aMediaId ) + { + if( KUidMediaTypeAudio == aMediaId.iMediaType ) + { + return iFourCC; + } + else + { + return TFourCC(); + } + } + +// ----------------------------------------------------------------------------- +// CAmrPayloadFormatRead::ConfigurePayloadFormatL +// Configure payload decoding parameters. +// ----------------------------------------------------------------------------- +// +void CAmrPayloadFormatRead::ConfigurePayloadFormatL( const TDesC8& aConfigParams ) + { + AMR_PAYLOAD_FORMAT_READ( "CAmrPayloadFormatRead::ConfigurePayloadFormatL (NB/WB)" ); + __ASSERT_ALWAYS( aConfigParams.Size() == sizeof( TMccCodecInfo ), + User::Leave( KErrArgument ) ); + + TMccCodecInfoBuffer infoBuffer; + infoBuffer.Copy( aConfigParams ); + + if ( !infoBuffer().iIsUpdate ) + { + __ASSERT_ALWAYS( infoBuffer().iHwFrameTime, User::Leave( KErrArgument ) ); + + iCInfo = infoBuffer(); + + AMR_PAYLOAD_FORMAT_READ5 ( "CAmrPayloadFormatRead::ConfigurePayloadFormatL \ + MaxPT: %d HWFS: %d FS: %d RED: %d" , iCInfo.iMaxPtime, iCInfo.iHwFrameTime, + iCInfo.iFrameSize, iCInfo.iRedundancyCount ); + + if ( !iPayloadDecoder ) + { + if ( KAmrCodecModeBandwidthEfficient == iCInfo.iCodecMode ) + { + iPayloadDecoder = CAmrPayloadDecoder::NewL( iIsNb ); + } + else if ( KAmrCodecModeOctetAlign == iCInfo.iCodecMode ) + { + iPayloadDecoder = CAmrPayloadDecoderOA::NewL( iIsNb ); + } + else + { + AMR_PAYLOAD_FORMAT_READ( "CAmrPayloadFormatRead::ConfigurePayloadFormatL KErrArgument" ); + User::Leave( KErrArgument ); + } + } + + iFramesPerPacket = iCInfo.iMaxPtime / iCInfo.iHwFrameTime; + iPayloadDecoder->SetFrameBlockCount( iFramesPerPacket ); + + if ( !iFrameBufferOne ) + { + iFrameBufferOne = CMMFDataBuffer::NewL( iCInfo.iFrameSize ); + } + if ( !iFrameBufferTwo ) + { + iFrameBufferTwo = CMMFDataBuffer::NewL( iCInfo.iFrameSize ); + } + + if ( iSourceBufOwnership ) + { + delete iSourceBuffer; + } + iSourceBuffer = NULL; + + TInt plSize = iCInfo.iFrameSize * iFramesPerPacket; + + if ( EAmrFecUsed == iCInfo.iAlgoUsed ) + { + AMR_PAYLOAD_FORMAT_READ( "CAmrPayloadFormatRead::ConfigurePayloadFormatL - Using AMR FEC" ); + + plSize + = ( 0 <= iCInfo.iMaxRed ) + ? iCInfo.iFrameSize * ( iFramesPerPacket + ( iCInfo.iMaxRed / iCInfo.iHwFrameTime ) ) + : iCInfo.iFrameSize * ( iFramesPerPacket + KMaxAmrRedCount ); + } + else if ( EGenRedUsed == iCInfo.iAlgoUsed ) + { + AMR_PAYLOAD_FORMAT_READ2( "CAmrPayloadFormatRead::ConfigurePayloadFormatL, RED LEVEL: %d", + iCInfo.iRedundancyCount ); + + if ( iCInfo.iRedundancyCount ) + { + plSize *= iCInfo.iRedundancyCount; + } + + CPayloadFormatRead* redDecoder + = static_cast( iClip ); + + TMccRedPayloadReadConfig config; + config.iRedBlockCount = iCInfo.iRedundancyCount; + config.iMaxPayloadSize = iCInfo.iFrameSize * iFramesPerPacket; + config.iNumOfEncodings = 1; + config.iRedPayloadType = iCInfo.iRedundantPayload; + config.InitPayloadTypes(); + config.iEncPayloadTypes[0] = iCInfo.iPayloadType; + TMccRedPayloadReadPckg pckg( config ); + redDecoder->ConfigurePayloadFormatL( pckg ); + } + else + { + // NOP + } + + iSourceBuffer = CreateClipBufferL( plSize, iSourceBufOwnership ); + } + else + { + UpdateConfigurationL( infoBuffer() ); + } + } + +// ----------------------------------------------------------------------------- +// CAmrPayloadFormatRead::UpdateConfigurationL +// Update payload decoder parameters +// ----------------------------------------------------------------------------- +// +void CAmrPayloadFormatRead::UpdateConfigurationL( const TMccCodecInfo& aCodecInfo ) + { + AMR_PAYLOAD_FORMAT_READ( "CAmrPayloadFormatRead::UpdateConfigurationL" ); + + if ( iCInfo.iMaxPtime != aCodecInfo.iMaxPtime ) + { + iFramesPerPacket = aCodecInfo.iMaxPtime / iCInfo.iHwFrameTime; + iPayloadDecoder->SetFrameBlockCount( iFramesPerPacket ); + + if ( iSourceBufOwnership ) + { + delete iSourceBuffer; + } + iSourceBuffer = NULL; + + TInt plSize = iCInfo.iFrameSize * iFramesPerPacket; + + if ( EAmrFecUsed == iCInfo.iAlgoUsed ) + { + plSize + = ( 0 <= iCInfo.iMaxRed ) + ? iCInfo.iFrameSize * ( iFramesPerPacket + ( iCInfo.iMaxRed / iCInfo.iHwFrameTime ) ) + : iCInfo.iFrameSize * ( iFramesPerPacket + KMaxAmrRedCount ); + } + else + { + AMR_PAYLOAD_FORMAT_READ( "CAmrPayloadFormatRead::ConfigurePayloadFormatL Not using AMR FEC" ) + } + + iSourceBuffer = CreateClipBufferL( plSize, iSourceBufOwnership ); + + // Initialize payload decoder + iPayloadDecoder->Initialize(); + + iCInfo.iMaxPtime = aCodecInfo.iMaxPtime; + } + + AMR_PAYLOAD_FORMAT_READ( "CAmrPayloadFormatRead::UpdateConfigurationL OUT" ) + } + +// ----------------------------------------------------------------------------- +// CAmrPayloadFormatRead::SendAmrEventToClient +// ----------------------------------------------------------------------------- +// +void CAmrPayloadFormatRead::SendAmrEventToClient( + TMccInternalEventType aEventType ) + { + TMccAmrEventData eventData; + TInt bitrate = ConvertModeToBitrate( iCmr ); + eventData.iModeRequestBitrate = bitrate; + + if ( iEventHandler ) + { + TMccEvent event; + event.iEventData = TMccAmrEventDataPackage( eventData ); + + TMccInternalEvent internalEvent( KMccAmrFormatterUid, + aEventType, + event ); + + iEventHandler->SendEventToClient( internalEvent ); + } +#ifdef TRACE_AMR_PAYLOAD_FORMAT_READ + else + { + AMR_PAYLOAD_FORMAT_READ ( "CAmrPayloadFormatRead::SendAmrEventToClient, \ +iEventHandler=NULL" ) + } +#endif + } + +// ----------------------------------------------------------------------------- +// CAmrPayloadFormatRead::CreateClipBufferL +// Creates buffer needed in data transfer with format readers clip. +// ----------------------------------------------------------------------------- +// +CMMFDataBuffer* CAmrPayloadFormatRead::CreateClipBufferL( + TUint aSize, TBool& aIsOwnBuffer ) + { + AMR_PAYLOAD_FORMAT_READ ( "CAmrPayloadFormatRead::CreateClipBufferL" ) + CMMFDataBuffer* buffer( NULL ); + + if ( iClip->CanCreateSourceBuffer() ) + { + if ( iClip->DataSourceType() == KUidMmfFormatDecode || + iClip->DataSourceType() == KMccMultiplexerUid ) + { + 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; + } + +// ----------------------------------------------------------------------------- +// CAmrPayloadFormatRead::ConvertModeToBitrate +// Gives corresponding bitrate for mode request depending +// on formatter mode (nb/wb) +// ----------------------------------------------------------------------------- +// +TInt CAmrPayloadFormatRead::ConvertModeToBitrate( TAmrModeRequest aModeRequest ) + { + if ( iIsNb && aModeRequest < KNumberOfNbModes ) + { + return KAmrNbModes[aModeRequest]; + } + + if ( !iIsNb && aModeRequest < KNumberOfWbModes ) + { + return KAmrWbModes[aModeRequest]; + } + + return 0; + } + +// ========================== OTHER EXPORTED FUNCTIONS ========================= + +// End of File