diff -r 000000000000 -r 1bce908db942 multimediacommscontroller/mmccdtmfpayloadformat/src/dtmfpayloaddecoder.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/multimediacommscontroller/mmccdtmfpayloadformat/src/dtmfpayloaddecoder.cpp Tue Feb 02 01:04:58 2010 +0200 @@ -0,0 +1,521 @@ +/* +* Copyright (c) 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: DTMF RTP payload decoder for named telephone events +* and tones. +* +*/ + + + + +// INCLUDES +#include +#include "dtmfpayloaddecoder.h" +#include "streamformatter.h" + +// CONSTANTS +const TInt KBitIndex = 8; +const TInt KReservedBits = 4; +const TUint KMaxEventInteger = 9; + +#ifdef VOIP_TRACE_ENABLED +#include +#endif + +// ======== MEMBER FUNCTIONS ======== + + +// --------------------------------------------------------------------------- +// CDTMFPayloadDecoder::CDTMFPayloadDecoder +// C++ default constructor can NOT contain any code, that +// might leave. +// --------------------------------------------------------------------------- +// +CDTMFPayloadDecoder::CDTMFPayloadDecoder() + { + } + +// --------------------------------------------------------------------------- +// CDTMFPayloadDecoder::NewL +// Two-phased constructor. +// --------------------------------------------------------------------------- +// +CDTMFPayloadDecoder* CDTMFPayloadDecoder::NewL() + { + DP_DTMF_DECODE( _L("CDTMFPayloadDecoder::NewL") ); + #ifdef VOIP_TRACE_ENABLED + VoipTrace( "%x %x", MCC_TRACE, MCC_DTMF_PLF_DEC_NEWL ); + #endif + + CDTMFPayloadDecoder* self = new( ELeave ) CDTMFPayloadDecoder; + return self; + } + +// --------------------------------------------------------------------------- +// CDTMFPayloadDecoder::~CDTMFPayloadDecoder +// Destructor. +// --------------------------------------------------------------------------- +// +CDTMFPayloadDecoder::~CDTMFPayloadDecoder() + { + DP_DTMF_DECODE( _L("CDTMFPayloadDecoder::~CDTMFPayloadDecoder") ); + #ifdef VOIP_TRACE_ENABLED + VoipTrace( "%x %x", MCC_TRACE, MCC_DTMF_PLF_DEC_DESTRUCTOR ); + #endif + + iEventArray.Reset(); + } + +// --------------------------------------------------------------------------- +// CDTMFPayloadDecoder::DecodeEventPayload +// Decodes one DTMF digit or mutually exclusive events from Event Payload +// Format packet. +// --------------------------------------------------------------------------- +// +/* + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | event |E|R| volume | duration | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +*/ +TInt CDTMFPayloadDecoder::DecodeEventPayload( CMMFBuffer* aSourceBuffer, + RArray& aEventInfos ) + { + DP_DTMF_DECODE( _L("CDTMFPayloadDecoder::DecodeEventPayload") ); + #ifdef VOIP_TRACE_ENABLED + VoipTrace( "%x %x %x", MCC_TRACE, MCC_DTMF_PLF_DEC_DECEVENTPAYLOAD, + aSourceBuffer ); + #endif + + if ( EDTMFPayloadFormatRedEvents == iPayloadFormat ) + { + return DecodeRedundantEventPayload( aSourceBuffer, aEventInfos ); + } + + if ( aSourceBuffer ) + { + TDes8& dataDes = + static_cast( aSourceBuffer )->Data(); + const TUint8* seekPtr = dataDes.Ptr(); + TInt events = dataDes.Length( ) / KEventBlockLengthInBytes; + + TStreamDecoder streamDecoder; + + streamDecoder.Initialize( const_cast( seekPtr ), 0, 0 ); + + while ( events-- ) + { + // Decode Event Field + TInt eventCode = streamDecoder.Decode( KEventFieldBits ); + TChar charRepresentation; + if ( KErrNone == ConvertToChar( eventCode, charRepresentation ) ) + { + iDecodedEventInfo.SetEvent( charRepresentation ); + + // Decode end bit for final packet + iDecodedEventInfo.SetEndBit( streamDecoder.Decode( 1 ) ); + + // Decode reserved bit + streamDecoder.Decode( 1 ); + + // Decode volume field. + // Volume field must be ignored if event + // is not DTMF digit (RFC 2833) + if ( KEventCodeForD > eventCode ) + { + iDecodedEventInfo.SetVolume( + streamDecoder.Decode(KVolFieldBits) ); + } + else + { + streamDecoder.Decode( KVolFieldBits ); + iDecodedEventInfo.SetVolume( 0 ); + } + + // Decode duration field + iDecodedEventInfo.SetDuration( + streamDecoder.Decode(KDurationFieldBits) ); + + // Time stamp from RTP header + iDecodedEventInfo.SetTimeStamp( iCurTimeStamp ); + + aEventInfos.Append( iDecodedEventInfo ); + + DP_DTMF_DECODE5( + _L( "Decoded event: %d, EndBit: %d, Volume: %d, Duration: %d" ), + static_cast( iDecodedEventInfo.Event() ), + iDecodedEventInfo.EndBit(), + iDecodedEventInfo.Volume(), + iDecodedEventInfo.Duration() ); + } + else + { + DP_DTMF_DECODE( _L( "CDTMFPayloadDecoder::DecodeEventPayload - Not supported event! ") ); + } + } + + return KErrNone; + } + else + { + return KErrArgument; + } + } + +// --------------------------------------------------------------------------- +// CDTMFPayloadDecoder::DecodeRedundantEventPayload +// Decodes events from Event Payload Format where is used Multi-Event +// Redundancy. +// --------------------------------------------------------------------------- +// +/* + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |F| block PT | timestamp offset | block length | + |1| 97 | 11200 | 4 | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |F| block PT | timestamp offset | block length | + |1| 97 | 11200 - 6400 = 4800 | 4 | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |F| Block PT | + |0| 97 | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | digit |E R| volume | duration | + | 9 |1 0| 7 | 1600 | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | digit |E R| volume | duration | + | 1 |1 0| 10 | 2000 | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | digit |E R| volume | duration | + | 1 |0 0| 20 | 400 | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ +TInt CDTMFPayloadDecoder::DecodeRedundantEventPayload( + CMMFBuffer* aSourceBuffer, + RArray& aEventInfos ) + { + DP_DTMF_DECODE( _L("CDTMFPayloadDecoder::DecodeRedundantEventPayload") ); + + #ifdef VOIP_TRACE_ENABLED + VoipTrace( "%x %x %x", MCC_TRACE, MCC_DTMF_PLF_DEC_DECREDEVPL, aSourceBuffer ); + #endif + + if ( aSourceBuffer ) + { + TDes8& dataDes = + static_cast( aSourceBuffer )->Data(); + const TUint8* seekPtr = dataDes.Ptr(); + + TStreamDecoder streamDecoder; + + streamDecoder.Initialize( const_cast( seekPtr ), 0, 0 ); + + aEventInfos.Reset(); + + // Count events in a payload from the redundancy headers + TInt eventCount( 0 ); + TBool FBitSet( ETrue ); + RArray< TTimeIntervalMicroSeconds32 > timeStamps; + + while ( FBitSet ) + { + eventCount++; + + FBitSet = static_cast( streamDecoder.Decode( 1 ) ); + streamDecoder.Decode( KBlockPTBits ); + + if ( FBitSet ) + { + TUint offset = streamDecoder.Decode( KTimeStampOffsetBits ); + timeStamps.Append( TTimeIntervalMicroSeconds32( + iCurTimeStamp.Int() - offset ) ); + } + else + { + timeStamps.Append( TTimeIntervalMicroSeconds32( + iCurTimeStamp.Int() ) ); + } + + // Jump to the beginning of next redundancy header + streamDecoder.Initialize( const_cast( seekPtr ), + eventCount * KEventBlockLengthInBytes, 0 ); + } + + // Count index of first real event. + // Last redundancy header consists of F-bit and PT only. + streamDecoder.Initialize( const_cast( seekPtr ), + eventCount * KEventBlockLengthInBytes - + KEventBlockLengthInBytes, KBitIndex ); + + // Decode all events from payload to the event info array. + for ( TInt i = 0; i < eventCount; i++ ) + { + // Decode Event Field + TInt eventCode = streamDecoder.Decode( KEventFieldBits ); + TChar charRepresentation; + + if ( KErrNone == ConvertToChar( eventCode, charRepresentation ) ) + { + iDecodedEventInfo.SetEvent( charRepresentation ); + + // Decode end bit for final packet + iDecodedEventInfo.SetEndBit( streamDecoder.Decode( 1 ) ); + + // Decode reserved bit + streamDecoder.Decode( 1 ); + + // Decode volume field. + iDecodedEventInfo.SetVolume( streamDecoder.Decode( + KVolFieldBits ) ); + + // Decode duration field + iDecodedEventInfo.SetDuration( streamDecoder.Decode( + KDurationFieldBits ) ); + + // Set time stamp + iDecodedEventInfo.SetTimeStamp( timeStamps[i] ); + + aEventInfos.Append( iDecodedEventInfo ); + } + else + { + DP_DTMF_DECODE( _L( "CDTMFPayloadDecoder::DecodeRedEventPayload" ) ); + DP_DTMF_DECODE( _L( "- Not supported event! ") ); + } + } + + timeStamps.Reset(); + + // Delete already played events from the beginning of aEventInfos + // array based on time stamp + TInt latestRecordedEventInd( iEventArray.Count() - 1 ); + + if ( 0 <= latestRecordedEventInd ) + { + while ( aEventInfos.Count() && aEventInfos[0].TimeStamp() + <= iEventArray[ latestRecordedEventInd ].TimeStamp() ) + { + // Redundant event has earlier time stamp than latest played + // event we must delete this. + aEventInfos.Remove( 0 ); + } + } + + // Copy count of accepted events to the end of iEventArray and delete + // same count from the beginning of array. Decoder must keep copies of + // EventInfos, because PayloadFormatRead may make Reset() for a + // aEventInfos Array. + for ( TInt j = 0; j < aEventInfos.Count(); j++ ) + { + iEventArray.Append( aEventInfos[ j ] ); + if ( KDTMFDefaultRedundancyCount < iEventArray.Count() ) + { + iEventArray.Remove( 0 ); + } + } + + return KErrNone; + } + else + { + return KErrArgument; + } + } + +// --------------------------------------------------------------------------- +// CDTMFPayloadDecoder::DecodeTonePayload +// Decodes tones from Tone Payload Format packet. +// Currently only DTMF tones are decoded (first tone). +// Format of line event tones are unclear. Are multiple parts containing +// line events encoded in one RTP packet or one part per RTP packet. +// No proper support at DevSound / AudioServer to play out tone payload. +// --------------------------------------------------------------------------- +// +/* + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | modulation |T| volume | duration | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |R R R R| frequency |R R R R| frequency | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |R R R R| frequency |R R R R| frequency | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ...... + + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |R R R R| frequency |R R R R| frequency | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +*/ +TInt CDTMFPayloadDecoder::DecodeTonePayload( CMMFBuffer* aSourceBuffer, + RArray& aToneInfos ) + { + DP_DTMF_DECODE( _L( "CDTMFPayloadDecoder::DecodeTonePayload" ) ); + #ifdef VOIP_TRACE_ENABLED + VoipTrace( "%x %x %x", MCC_TRACE, MCC_DTMF_PLF_DEC_DECTONEPL, aSourceBuffer ); + #endif + + if ( aSourceBuffer ) + { + TDes8& dataDes = + static_cast( aSourceBuffer )->Data(); + const TUint8* seekPtr = dataDes.Ptr(); + + TStreamDecoder streamDecoder; + + streamDecoder.Initialize( const_cast( seekPtr ), 0, 0 ); + + // Encode modulation field + iDecodedToneInfo.SetModulation( streamDecoder.Decode( + KModulationBits ) ); + + // Encode T bit + iDecodedToneInfo.SetTBit( streamDecoder.Decode( 1 ) ); + + // Encode Volume Field + iDecodedToneInfo.SetVolume( streamDecoder.Decode( KVolFieldBits ) ); + + // Encode Duration Field + iDecodedToneInfo.SetDuration( streamDecoder.Decode( + KDurationFieldBits ) ); + + // Encode four R(eserved) bits + streamDecoder.Decode( KReservedBits ); + + // Encode first Frequency Field + iDecodedToneInfo.SetLowFrequency( streamDecoder.Decode( + KFrequencyBits ) ); + + // Encode four R(eserved) bits + streamDecoder.Decode( KReservedBits ); + + // Encode second Frequency Field + iDecodedToneInfo.SetHighFrequency( streamDecoder.Decode( + KFrequencyBits ) ); + + aToneInfos.Append( iDecodedToneInfo ); + + return KErrNone; + } + else + { + return KErrArgument; + } + } + +// --------------------------------------------------------------------------- +// CDTMFPayloadDecoder::PayloadFormat +// Returns payload format in use. +// --------------------------------------------------------------------------- +// +TDTMFPayloadFormat CDTMFPayloadDecoder::PayloadFormat( ) const + { + DP_DTMF_DECODE2( _L( "CDTMFPayloadDecoder::PayloadFormat - Format: %d" ), + iPayloadFormat ); + + return iPayloadFormat; + } + +// --------------------------------------------------------------------------- +// CDTMFPayloadDecoder::SetPayloadFormat +// Sets payload format in use. +// --------------------------------------------------------------------------- +// +TInt CDTMFPayloadDecoder::SetPayloadFormat( + TDTMFPayloadFormat aPayloadFormat ) + { + DP_DTMF_DECODE2( _L( "CDTMFPayloadDecoder::SetPayloadFormat - Format: %d" ), + aPayloadFormat ); + #ifdef VOIP_TRACE_ENABLED + VoipTrace( "%x %x %d", MCC_TRACE, MCC_DTMF_PLF_DEC_SETPLF, aPayloadFormat ); + #endif + + if ( EDTMFPayloadFormatEvent != aPayloadFormat + && EDTMFPayloadFormatTone != aPayloadFormat + && EDTMFPayloadFormatRedEvents != aPayloadFormat ) + { + return KErrNotSupported; + } + else + { + iPayloadFormat = aPayloadFormat; + } + + return KErrNone; + } + +// --------------------------------------------------------------------------- +// CDTMFPayloadDecoder::SetCurTimeStamp +// Sets the time stamp of a RTP packet containing payload which is decoded +// next. +// --------------------------------------------------------------------------- +// +void CDTMFPayloadDecoder::SetCurTimeStamp( + const TTimeIntervalMicroSeconds32& aTimeStamp ) + { + DP_DTMF_DECODE2( _L( "CDTMFPayloadDecoder::SetCurTimeStamp - TimeStamp: %d" ), + aTimeStamp.Int() ); + + #ifdef VOIP_TRACE_ENABLED + VoipTrace( "%x %x %d", MCC_TRACE, MCC_DTMF_PLF_DEC_SETCURTS, aTimeStamp.Int() ); + #endif + + iCurTimeStamp = aTimeStamp; + } + +// --------------------------------------------------------------------------- +// CDTMFPayloadDecoder::ConvertToChar +// Converts integer presentation used in a payload format to the character. +// --------------------------------------------------------------------------- +// +TInt CDTMFPayloadDecoder::ConvertToChar( TUint aEvent, TChar& aChar ) const + { + TInt conversionResult( KErrNone ); + + if ( aEvent <= KMaxEventInteger ) + { + aChar = TChar( aEvent + '0' ); + } + else + { + switch ( aEvent ) + { + case KEventCodeForAsterisk: + aChar = '*'; + break; + case KEventCodeForHashMark: + aChar = '#'; + break; + case KEventCodeForA: + aChar = 'a'; + break; + case KEventCodeForB: + aChar = 'b'; + break; + case KEventCodeForC: + aChar = 'c'; + break; + case KEventCodeForD: + aChar = 'd'; + break; + default: + conversionResult = KErrNotSupported; + break; + } + } + + return conversionResult; + } + +// End of File