This release addresses the following issues:
1. The crash bug fix when receiving file
2. Now the sending is based on MSRP messages, there is no longer file receiving or sending. Client sends data as MSRP was designed.
3. Soma MSRP stack was created so that the client told the correct session-id, Symbian stack generated it by itself. This is not allowed, it was changed so that clients tell the session-id (same as used in SIP INVITE).
4. Unnecessary division of data to chunks removed when there is no need to interrupt sending. The message is sent in as few chunks as possible.
5. Stack can now receive files and chunks with ?unlimited? size. Old stack wrote the incoming data to memory and did not utilize disk space until the end of chunk was reached (large chunks from another client crashed it).
6. Now when writing the incoming data to file, it will take into account the byte-range header values. So, this complies with the RFC4975 requirements that stack must be able to handle chunks that come in any sequence.
7. Some buffering changes to outgoing/incoming data.
8. The outgoing data is now checked that it does not contain the created transaction-id before sending the data.
9. MSRP success reports are now implemented and tested against servers.
10. Progress report system fixed so progress is now visible on client (all the way to 100%).
11. Message Cancel receiving / Cancel sending now corrected and made to work as rfc4975 requires. (termination from sender and error code from receiver when cancelling).
12. Bug correction related to messages received not belonging to any session, old stack implementation did send error response, but after response was written it did give the buffer to client anyway. Now corrected.
/*
* Copyright (c) 2002-2003 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:
*
*/
// INCLUDE FILES
#include <e32base.h>
#include <e32std.h>
#include "rtputil.h"
#include "rtpsdes.h"
#include "rtppacket.h"
#include "rtpmanager.h"
// CONSTANTS
const TInt KRtpVersion = 2; // Current protocol version
const TUint8 KNullTerm( '\0' );
const TUint KMinRtpHeaderLen( 12 );
const TUint KMinRtcpAppLen( 3 );
const TInt KCSRCListMax = 15;
// ================= MEMBER FUNCTIONS =======================
// ---------------------------------------------------------------------------
// C++ default constructor can NOT contain any code, that
// might leave.
// ---------------------------------------------------------------------------
//
CRtpPacket::CRtpPacket( const TUint32* aRtpTimeRates ) :
iSize( 0 ),
iProfileRTPTimeRates( aRtpTimeRates )
{
}
// ---------------------------------------------------------------------------
// Symbian 2nd phase constructor can leave.
// ---------------------------------------------------------------------------
//
void CRtpPacket::ConstructL( TUint aPacketSize )
{
iBuf = HBufC8::NewL( aPacketSize );
iData = const_cast<TUint8*>( iBuf->Des().Ptr() );
iDataPtr = iData;
iExdataAlloc =EFalse;
iCsrcAlloc= EFalse;
}
// ---------------------------------------------------------------------------
// Two-phased constructor.
// ---------------------------------------------------------------------------
//
CRtpPacket* CRtpPacket::NewL( TUint aPacketSize, const TUint32* aRtpTimeRates )
{
CRtpPacket* self = new ( ELeave ) CRtpPacket( aRtpTimeRates );
CleanupStack::PushL( self );
self->ConstructL( aPacketSize );
CleanupStack::Pop(); //self
return self;
}
// ---------------------------------------------------------------------------
// Destructor
// ---------------------------------------------------------------------------
//
CRtpPacket::~CRtpPacket()
{
delete iBuf; iBuf = NULL;
}
// ---------------------------------------------------------------------------
//
//
// ---------------------------------------------------------------------------
//
void CRtpPacket::RtpPacketReset()
{
iSize = 0;
iDataPtr = iData;
}
// ---------------------------------------------------------------------------
// CRtpPacket::RtpPacketResetPtr()
//
// ---------------------------------------------------------------------------
//
void CRtpPacket::RtpPacketResetPtr()
{
iDataPtr = iData;
}
// ---------------------------------------------------------------------------
// CRtpPacket::RtpPacketBuildRtp()
//
// ---------------------------------------------------------------------------
//
TInt CRtpPacket::RtpPacketBuildRtp( TRtpPacketStreamParam* aStreamParam,
TRtpPacketIOParam* aInitParam )
{
//Get a pointer to the beginning of iBuf
TUint8* dataP = iData;
//Fill dataP with binary zeroes (i.e. 0x00), replacing any existing content
Mem::FillZ( dataP, KMinRtpHeaderLen );
/****************************
* dataP[0] = 8 bit *
* *
* 2 bit = version *
* 1 bit = padding *
* 1 bit = CRSRC Count *
* 4 bit = extension *
****************************/
//version (2 bit)
// 0111001
// 1100000
// -------
// 1111001
dataP[0] |= ( KRtpVersion << 6 );
// padding (1 bit)
dataP[0] |= static_cast<TUint8>( ( aInitParam->TRTP.padding << 5 ) );
// header extension (1 bit)
if ( aInitParam->TRTP.fHeaderExtension)
{
dataP[0] |= ( 1 << 4 );
}
// CC = 0 (1 bit)
/****************************
* dataP[1] = 8 bit *
* *
* 1 bit = marker *
* 1 bit = payload type *
****************************/
// marker (1 bit)
dataP[1] |= static_cast<TUint8>( aInitParam->TRTP.marker << 7 );
// payload type (7 bit)
// confirm that payload can fit the 7 bit (0 - 127)
if(aStreamParam->TRTP.payload > KPayloadTypeMax )
{
return KErrTooBig;
}
dataP[1] |= aStreamParam->TRTP.payload;
//set the pointer to point at the beginning of the sequence number.
dataP += 2;
// sequence number (16 bit)
Write16( dataP, aStreamParam->TRTP.seqNum );
//set the pointer to point at the beginning of the time stamp.
dataP += 2;
// RTP timestamp (32 bit)
Write32( dataP, aStreamParam->TRTP.timeStamp );
//set the pointer to point at the beginning of SSRC.
dataP += 4;
// SSRC (32 bit)
Write32( dataP, aStreamParam->TRTP.SSRC );
//set the pointer to point to the first bit after SSRC
dataP += 4;
if ( aInitParam->TRTP.fHeaderExtension )
{
//calculate 8 bit values to 32 bit words
TInt16 length32 =
static_cast<TInt16>( aInitParam->TRTP.extension.length / 4 );
//if length mod 4 != 0,
if ( aInitParam->TRTP.extension.length % 4 )
{
length32++;
}
// header extension type defined by profile
// aInitParam->TRTP.extension.type is 32-bit and part of the API
// (i.e. unchangeable), so we have to extract the 16-LSB
Write16( dataP, aInitParam->TRTP.extension.type & 0xFFFF );
dataP += 2;
// header extension length in number of 32-bit words
Write16( dataP, length32 );
dataP += 2;
// header extension data
if (length32 && aInitParam->TRTP.extension.data )
{
Mem::FillZ( dataP, length32 * 4 );
for ( TInt i = 0; i < aInitParam->TRTP.extension.length; i++ )
{
dataP[i] = aInitParam->TRTP.extension.data[i];
}
dataP += ( length32 * 4 );
}
}
//Copy(Target, Source, Length)
Mem::Copy( dataP, aInitParam->TRTP.payloadData,
aInitParam->TRTP.payloadDataLen );
iSize = aInitParam->TRTP.payloadDataLen + ( dataP - iData );
return KErrNone;
}
// ---------------------------------------------------------------------------
// TInt CRtpPacket::RtpPacketBuildRtcp()
//
// ---------------------------------------------------------------------------
//
TInt CRtpPacket::RtpPacketBuildRtcp( TRtpPacketStreamParam* aStreamParam,
TRtpPacketIOParam* aInitParam )
{
Mem::FillZ( iDataPtr, 4 );
// version
iDataPtr[0] |= ( KRtpVersion << 6 );
// padding = 0
iDataPtr[0] |= ( 0 << 5 );
// source count
iDataPtr[0] |= static_cast<TUint8>( aInitParam->TRTCP_HEADER.sourceCount );
// packet type
iDataPtr[1] = static_cast<TUint8>( aInitParam->TRTCP_HEADER.pt );
iDataPtr += 2;
// length of RTCP packet
// aInitParam->TRTCP_HEADER.length is 32-bit and part of the API
// (i.e. unchangeable), so we have to extract the 16-LSB
Write16( iDataPtr, aInitParam->TRTCP_HEADER.length & 0xFFFF );
iDataPtr += 2;
// SSRC of sender in case of RR
if ( aInitParam->TRTCP_HEADER.pt == ERTCP_RR )
{
Write32( iDataPtr, aStreamParam->TRTCP_HEADER.SSRC );
iDataPtr += 4;
}
iSize += ( aInitParam->TRTCP_HEADER.length + 1 ) * 4;
return KErrNone;
}
// ---------------------------------------------------------------------------
// TInt CRtpPacket::RtpPacketBuildApp()
//
// ---------------------------------------------------------------------------
//
TInt CRtpPacket::RtpPacketBuildApp( TRtpPacketStreamParam* aStreamParam,
TRtpPacketIOParam* aInitParam )
{
// SSRC
Write32( iDataPtr, aStreamParam->TRTCP_APP.SSRC );
iDataPtr += 4;
// name
Mem::Copy( iDataPtr, aInitParam->TRTCP_APP.name, 4 );
iDataPtr += 4;
// application data
Mem::Copy( iDataPtr, aInitParam->TRTCP_APP.appData,
aInitParam->TRTCP_APP.appDataLen );
iDataPtr += aInitParam->TRTCP_APP.appDataLen;
return KErrNone;
}
// ---------------------------------------------------------------------------
// TInt CRtpPacket::RtpPacketBuildBye()
//
// ---------------------------------------------------------------------------
//
TInt CRtpPacket::RtpPacketBuildBye( TRtpPacketStreamParam* aStreamParam,
TRtpPacketIOParam* aInitParam )
{
TUint8 theIndex( 0 );
// SSRC
Write32( iDataPtr, aStreamParam->TRTCP_BYE.SSRC );
iDataPtr += 4;
// reason
iDataPtr[0] = static_cast<TUint8>( aInitParam->TRTCP_BYE.reasonSize );
iDataPtr += 1;
Mem::Copy( iDataPtr, aInitParam->TRTCP_BYE.reason,
aInitParam->TRTCP_BYE.reasonSize );
iDataPtr += aInitParam->TRTCP_BYE.reasonSize;
// padding
if ( aInitParam->TRTCP_BYE.paddingSize != 0 )
{
for ( theIndex = 0; theIndex < aInitParam->TRTCP_BYE.paddingSize;
theIndex++ )
{
iDataPtr[theIndex] = KNullTerm;
}
iDataPtr += aInitParam->TRTCP_BYE.paddingSize;
}
return KErrNone;
}
// ---------------------------------------------------------------------------
// TInt CRtpPacket::RtpPacketBuildRr()
//
// ---------------------------------------------------------------------------
//
TInt CRtpPacket::RtpPacketBuildRr( TRtpPacketStreamParam* aStreamParam,
TRtpPacketIOParam* aInitParam )
{
// SSRC
Write32( iDataPtr, aStreamParam->TRTCP_RR.SSRC );
iDataPtr += 4;
// fraction lost
iDataPtr[0] = aStreamParam->TRTCP_RR.fractionLost;
iDataPtr++;
// cumulative number of packets lost
Write24( iDataPtr, aStreamParam->TRTCP_RR.cumNumPacketsLost );
iDataPtr += 3;
// extended highest sequence number received
Write32( iDataPtr, aStreamParam->TRTCP_RR.seqNumReceived );
iDataPtr += 4;
// interarrival jitter
Write32( iDataPtr, aStreamParam->TRTCP_RR.arrivalJitter );
iDataPtr += 4;
// last SR timestamp
Write32( iDataPtr, aInitParam->TRTCP_RR.lastSRTimeStamp );
iDataPtr += 4;
// delay since last SR timestamp
Write32( iDataPtr, aInitParam->TRTCP_RR.delaySinceLSR );
iDataPtr += 4;
return KErrNone;
}
// ---------------------------------------------------------------------------
// TInt CRtpPacket::RtpPacketBuildSr()
//
// ---------------------------------------------------------------------------
//
TInt CRtpPacket::RtpPacketBuildSr( TRtpPacketStreamParam* aStreamParam,
TRtpPacketIOParam* aInitParam )
{
// SSRC
Write32( iDataPtr, aStreamParam->TRTCP_SR.SSRC );
iDataPtr += 4;
// NTP timestamp (seconds)
Write32( iDataPtr, aInitParam->TRTCP_SR.NTPTimeStampSec );
iDataPtr += 4;
// NTP timestamp (fraction)
Write32( iDataPtr, aInitParam->TRTCP_SR.NTPTimeStampFrac );
iDataPtr += 4;
// RTP timestamp
Write32( iDataPtr, aInitParam->TRTCP_SR.timeStamp );
iDataPtr += 4;
// sender's packet count
Write32( iDataPtr, aStreamParam->TRTCP_SR.numPacketsSent );
iDataPtr += 4;
// sender's octet count
Write32( iDataPtr, aStreamParam->TRTCP_SR.cumNumOctetsSent );
iDataPtr += 4;
return KErrNone;
}
// ---------------------------------------------------------------------------
// TInt CRtpPacket::RtpPacketBuildSdes()
//
// ---------------------------------------------------------------------------
//
TInt CRtpPacket::RtpPacketBuildSdes( TRtpPacketStreamParam* aStreamParam,
TRtpPacketIOParam* aInitParam )
{
TUint8 theIndex( 0 );
// SSRC
Write32( iDataPtr, aStreamParam->TRTCP_SDES.SSRC );
iDataPtr += 4;
// SDES items
for ( theIndex = 0; theIndex < ERTCP_NUM_OF_SDES_ITEMS; theIndex++ )
{
if ( aInitParam->TRTCP_SDES.sdesItemsSize[theIndex] != 0 )
{
iDataPtr[0] = static_cast<TUint8>( theIndex + 1 );
iDataPtr[1] = static_cast<TUint8>(
aInitParam->TRTCP_SDES.sdesItemsSize[theIndex] );
iDataPtr += 2;
Mem::Copy( iDataPtr,
aInitParam->TRTCP_SDES.sdesItems[theIndex],
aInitParam->TRTCP_SDES.sdesItemsSize[theIndex] );
iDataPtr += aInitParam->TRTCP_SDES.sdesItemsSize[theIndex];
}
}
// include end of list null octet
iDataPtr[0] = KNullTerm;
iDataPtr++;
// padding
if ( aInitParam->TRTCP_SDES.paddingSize != 0 )
{
for ( theIndex = 0; theIndex < aInitParam->TRTCP_SDES.paddingSize;
theIndex++ )
{
iDataPtr[theIndex] = KNullTerm;
}
iDataPtr += aInitParam->TRTCP_SDES.paddingSize;
}
return KErrNone;
}
// ---------------------------------------------------------------------------
// TInt CRtpPacket::RtpPacketBuild()
//
// ---------------------------------------------------------------------------
//
TInt CRtpPacket::RtpPacketBuild( TRtpPacketStreamParam* aStreamParam,
TRtpPacketIOParam* aInitParam )
{
TInt result( KErrNone );
if ( !aStreamParam || !aInitParam )
{
return KErrUnderflow;
}
// build the packet content
switch ( iType )
{
case ERTP:
result = RtpPacketBuildRtp( aStreamParam, aInitParam );
break;
case ERTCP_HEADER:
result = RtpPacketBuildRtcp( aStreamParam, aInitParam );
break;
case ERTCP_SR:
result = RtpPacketBuildSr( aStreamParam, aInitParam );
break;
case ERTCP_RR:
result = RtpPacketBuildRr( aStreamParam, aInitParam );
break;
case ERTCP_SDES:
result = RtpPacketBuildSdes( aStreamParam, aInitParam );
break;
case ERTCP_BYE:
result = RtpPacketBuildBye( aStreamParam, aInitParam );
break;
case ERTCP_APP:
result = RtpPacketBuildApp( aStreamParam, aInitParam );
break;
default:
result = ERTCP_PACKET_ERROR; //unknown packet type
break;
}
return result;
}
// ---------------------------------------------------------------------------
// TRtpSSRC CRtpPacket::RtpPacketGetSSRC()
// assumed to be called for an RTCP packet only after
// RTCP_HEADER has determined the packet type
// ---------------------------------------------------------------------------
TRtpSSRC CRtpPacket::RtpPacketGetSSRC()
{
TUint8* dataP;
// parse the packet content
switch ( iType )
{
case ERTP:
{
dataP = iData + 8;
return ( Read32( dataP ) );
}
case ERTCP_HEADER:
{
dataP = iData + 4;
return ( Read32( dataP ) );
}
case ERTCP_SR:
case ERTCP_RR:
case ERTCP_SDES:
case ERTCP_BYE:
case ERTCP_APP:
{
dataP = iDataPtr;
return ( Read32( dataP ) );
}
default:
break;
}
return 0;
}
// ----------------------------------------------------------------------------
// CRtpPacket::RtpPacketGetPayloadType()
// ----------------------------------------------------------------------------
//
TRtpPayloadType CRtpPacket::RtpPacketGetPayloadType()
{
TUint8* dataP = iData;
// payload type
return static_cast<TUint8>( dataP[1] & 0x7F );
}
// ----------------------------------------------------------------------------
// CRtpPacket::RtpPacketProcessRtp()
// ----------------------------------------------------------------------------
//
TRtpRtcpEnum CRtpPacket::RtpPacketProcessRtpL(
TRtpPacketStreamParam* aStreamParam,
TRtpPacketIOParam* aExtractParam )
{
RTP_DEBUG_PACKET( "CRtpPacket::RtpPacketProcessRtpL Entry" );
TInt k;
TInt err( KErrNone );
TUint8* dataP = iData;
// version
// 0xC0 = 1100 0000
// & 0xC0 removes all ones except the version number from the bit stream
//
// 11011011
// 11000000
// --------
// 11000000 >> 6 = 00000011
if ( ( ( dataP[0] & 0xC0 ) >> 6 ) != KRtpVersion )
{
RTP_DEBUG_DETAIL( "RtpPacketProcess: invalid version" );
return ERTCP_PACKET_ERROR;
}
// padding
// 0x20 = 0010 0000
//
// Checks if padding bit is set
if ( dataP[0] & 0x20 )
{
// The last octet of the packet must contain a valid octet count
// ( octet count < the total packet lenght minus the header size)
if ( ( iSize - iData[ iSize - 1] - KMinRtpHeaderSize ) > 0 )
{
aExtractParam->TRTP.padding = 1;
// The last octet of the padding contains a count of how many
// padding octets should be ignored, including itself.
iSize -= iData[iSize - 1];
}
else
{
// Invalid padding value
RTP_DEBUG_DETAIL( "RtpPacketProcess: invalid padding size" );
return ERTCP_PACKET_ERROR;
}
}
else //padding bit == 0
{
aExtractParam->TRTP.padding = 0;
}
// header extension
aExtractParam->TRTP.fHeaderExtension =
static_cast<TUint8>( ( dataP[0] & 0x10 ) >> 4 );
// CC
aExtractParam->TRTP.numCSRC = static_cast<TUint8>( dataP[0] & 0x0F );
// marker
aExtractParam->TRTP.marker =
static_cast<TUint8>( ( dataP[1] & 0x80 ) >> 7 );
// payload type
aStreamParam->TRTP.payload = static_cast<TUint8>( dataP[1] & 0x7F );
/**
* The payload type must be known, and in particular it must not
* be equal to SR or RR[RFC3550]
*
* 7 bit (= 127) is only reserved for payload, so no need to check
* that payload differ from SR (SR = 200) and RR (RR = 201)
* Since it always &0x7F so there is no possiblility to be more than
* 127
**/
dataP += 2;
// sequence number
aStreamParam->TRTP.seqNum = static_cast<TUint16>( Read16( dataP ) );
dataP += 2;
// RTP timestamp
aStreamParam->TRTP.timeStamp = Read32( dataP );
dataP += 4;
// SSRC
aStreamParam->TRTP.SSRC = Read32( dataP );
dataP += 4;
// CSRCs
if ( aExtractParam->TRTP.numCSRC >0 )
{
// Calculate the minimum required size of the remainder of this
// packet, in number of 8-bit words
TInt minRequiredSizeLeft = aExtractParam->TRTP.numCSRC * 4;
// Make sure there is are CSRCs to read
if ( ( iSize - ( dataP - iData ) ) < minRequiredSizeLeft )
{
RTP_DEBUG_DETAIL( "RtpPacketProcess: invalid CSRC size" );
return ERTCP_PACKET_ERROR;
}
// Originally Allocate memory for all CSRC:s
//it will have memeory resouce problem so only allocate when
// CSRC<2
if ( aExtractParam->TRTP.numCSRC < KCSRCListMax )
{
if ( !aExtractParam->TRTP.CSRCarray )
{
TRAP( err,
aExtractParam->TRTP.CSRCarray =
static_cast<TUint32*>(
User::AllocL( sizeof(TUint32) * aExtractParam->TRTP.numCSRC ) )
);
if (err==0)
{
iCsrcAlloc = ETrue;
}
}
if ( err || !aExtractParam->TRTP.CSRCarray )
{
RTP_DEBUG_DETAIL( "RtpPacketProcess: CSRC missing" );
return ERTCP_PACKET_ERROR;
}
int count=0;
for ( k = 0; k < aExtractParam->TRTP.numCSRC; k++ )
{
// CSRCs ignored
TUint32 temp =Read32( dataP );
if (!temp)
{
return ERTCP_PACKET_ERROR;
}
aExtractParam->TRTP.CSRCarray[k] = Read32( dataP );
dataP += 4;
count ++;
}
if (count!= aExtractParam->TRTP.numCSRC)
{
RTP_DEBUG_DETAIL( "RtpPacketProcess: numCSRC is not matched" );
return ERTCP_PACKET_ERROR;
}
}
else
{
for ( k = 0; k < aExtractParam->TRTP.numCSRC; k++ )
{
// CSRCs ignored
dataP += 4;
}
}
}
if ( aExtractParam->TRTP.fHeaderExtension )
{
// Make sure there is a header extension to read
if ( ( iSize - ( dataP - iData ) ) < 4 )
{
RTP_DEBUG_DETAIL( "RtpPacketProcess: invalid extension size" );
return ERTCP_PACKET_ERROR;
}
// header extension type defined by profile
aExtractParam->TRTP.extension.type = Read16( dataP );
dataP += 2;
// header extension length in number of 32-bit words
aExtractParam->TRTP.extension.length = Read16( dataP );
dataP += 2;
// Calculate the extension length in number of 8-bit words
TInt extensionLen8 = aExtractParam->TRTP.extension.length * 4;
// Make sure the extension length is valid
if ( ( iSize - ( dataP - iData ) ) < extensionLen8 )
{
RTP_DEBUG_DETAIL( "RtpPacketProcess: invalid extension length" );
return ERTCP_PACKET_ERROR;
}
if ( !aExtractParam->TRTP.extension.data )
{
TRAP( err,
aExtractParam->TRTP.extension.data = static_cast<TUint8*>(
User::AllocL( aExtractParam->TRTP.extension.length * 4 ) )
);
if(err==KErrNone)
{
iExdataAlloc= ETrue;
}
}
if ( err || !aExtractParam->TRTP.extension.data )
{
RTP_DEBUG_DETAIL( "RtpPacketProcess: extension missing" );
return ERTCP_PACKET_ERROR;
}
// header extension data
for ( k = 0; k < aExtractParam->TRTP.extension.length*4; k++ )
{
aExtractParam->TRTP.extension.data[k] = dataP[k];
}
dataP += ( aExtractParam->TRTP.extension.length * 4 );
}
// Make sure there is a payload
if ( ( iSize - ( dataP - iData ) ) > 0 )
{
aExtractParam->TRTP.payloadDataLen = iSize - ( dataP - iData );
aExtractParam->TRTP.payloadData = static_cast<TText8*>( dataP );
}
else
{
aExtractParam->TRTP.payloadDataLen = 0;
aExtractParam->TRTP.payloadData = NULL;
RTP_DEBUG_DETAIL( "RtpPacketProcess: packet length is 0" );
}
RTP_DEBUG_PACKET( "CRtpPacket::RtpPacketProcessRtpL Exit" );
return ERTCP_NO_ERROR;
}
// ----------------------------------------------------------------------------
// CRtpPacket::RtpPacketProcessRtcp()
// ----------------------------------------------------------------------------
//
TRtpRtcpEnum CRtpPacket::RtpPacketProcessRtcp(
TRtpPacketStreamParam* aStreamParam,
TRtpPacketIOParam* aExtractParam )
{
// version
if ( ( ( iDataPtr[0] & 0xC0 ) >> 6 ) != KRtpVersion )
{
RTP_DEBUG_DETAIL( "ERROR: Wrong Rtp version in header" );
return ERTCP_PACKET_ERROR;
}
// padding
if ( iDataPtr[0] & 0x20 )
{
iSize -= iData[iSize - 1];
}
// determine RTCP packet type
aExtractParam->TRTCP_HEADER.pt =
static_cast<TRtpPacketType>( iDataPtr[1] );
if ( ( aExtractParam->TRTCP_HEADER.pt != ERTCP_SR ) &&
( aExtractParam->TRTCP_HEADER.pt != ERTCP_RR ) &&
( aExtractParam->TRTCP_HEADER.pt != ERTCP_SDES ) &&
( aExtractParam->TRTCP_HEADER.pt != ERTCP_BYE ) &&
( aExtractParam->TRTCP_HEADER.pt != ERTCP_APP ) )
{
RTP_DEBUG_DETAIL( "ERROR: Incorrect packet type in header" );
return ERTCP_PACKET_ERROR;
}
// source/report Count
aExtractParam->TRTCP_HEADER.sourceCount = ( iDataPtr[0] & 0x1F );
iDataPtr += 2;
aExtractParam->TRTCP_HEADER.length =
static_cast<TInt>( Read16( iDataPtr ) );
if ( aExtractParam->TRTCP_HEADER.length * 4 > iSize )
{
RTP_DEBUG_DETAIL( "ERROR: Incorrect packet size in header" );
return ERTCP_PACKET_ERROR;
}
iDataPtr += 2;
// SSRC of sender in case of RR
if ( aExtractParam->TRTCP_HEADER.pt == ERTCP_RR )
{
aStreamParam->TRTCP_HEADER.SSRC = Read32( iDataPtr );
iDataPtr += 4;
}
return ERTCP_NO_ERROR;
}
// ----------------------------------------------------------------------------
// CRtpPacket::RtpPacketProcessApp()
// ----------------------------------------------------------------------------
//
TRtpRtcpEnum CRtpPacket::RtpPacketProcessAppL(
TRtpPacketStreamParam* aStreamParam,
TRtpPacketIOParam* aExtractParam )
{
TInt err( KErrNone );
// TRTCP_APP.totalPacketLen is the 32-bit packet length MINUS ONE.
TUint totalLen( aStreamParam->TRTCP_APP.totalPacketLen );
// Calculate the length of the data in the packet in number of 8-bit words
TUint appDataLen8 = ( totalLen + 1 - KMinRtcpAppLen ) * 4;
// The packet is faulty if the total length of the packet is results in a
// negative memory allocation . Also, it cannot be too big due to framework
// restrictions on memory allocation.
if ( ( totalLen + 1 < KMinRtcpAppLen ) ||
( sizeof( TUint8 ) * appDataLen8 > ( KMaxTInt / 2 ) ) )
{
return ERTCP_PACKET_ERROR;
}
// SSRC
aStreamParam->TRTCP_APP.SSRC = Read32( iDataPtr );
iDataPtr += 4;
// name
Mem::Copy( aExtractParam->TRTCP_APP.name, iDataPtr, 4 );
iDataPtr += 4;
// Allocate memory for application data
TRAP ( err,
aExtractParam->TRTCP_APP.appData =
static_cast<TUint8*>
(
User::AllocL( sizeof( TUint8 ) * appDataLen8 ) )
);
if ( err )
{
return ERTCP_PACKET_ERROR;
}
Mem::Copy( aExtractParam->TRTCP_APP.appData, iDataPtr, appDataLen8 );
iDataPtr += appDataLen8;
aExtractParam->TRTCP_APP.appDataLen = appDataLen8;
return ERTCP_NO_ERROR;
}
// ----------------------------------------------------------------------------
// CRtpPacket::RtpPacketProcessBye()
// ----------------------------------------------------------------------------
//
TRtpRtcpEnum CRtpPacket::RtpPacketProcessByeL(
TRtpPacketStreamParam* aStreamParam,
TRtpPacketIOParam* aExtractParam )
{
TInt err;
TUint8 theIndex( 0 );
// SSRC
aStreamParam->TRTCP_BYE.SSRC = Read32( iDataPtr );
iDataPtr += 4;
// reason
aExtractParam->TRTCP_BYE.reasonSize = iDataPtr[0];
iDataPtr += 1;
TRAP ( err, aExtractParam->TRTCP_BYE.reason = static_cast<TText8*>(
User::AllocL( sizeof( TText8 ) *
( aExtractParam->TRTCP_BYE.reasonSize + 1 /* trailing NULL */) ) )
);
if ( err )
{
return ERTCP_PACKET_ERROR;
}
Mem::Copy( aExtractParam->TRTCP_BYE.reason, iDataPtr,
aExtractParam->TRTCP_BYE.reasonSize );
*( aExtractParam->TRTCP_BYE.reason + aExtractParam->TRTCP_BYE.reasonSize )
= KNullTerm;
iDataPtr += aExtractParam->TRTCP_BYE.reasonSize;
// calculate size of padding
if ( ( 1 + aExtractParam->TRTCP_BYE.reasonSize ) % 4 != 0 )
{
aExtractParam->TRTCP_BYE.paddingSize =
4 - ( 1 + aExtractParam->TRTCP_BYE.reasonSize ) % 4;
}
else
{
aExtractParam->TRTCP_BYE.paddingSize = 0;
}
for ( theIndex = 0; theIndex < aExtractParam->TRTCP_BYE.paddingSize;
theIndex++ )
{
iDataPtr++;
}
return ERTCP_NO_ERROR;
}
// ----------------------------------------------------------------------------
// CRtpPacket::RtpPacketProcessRr()
// ----------------------------------------------------------------------------
//
TRtpRtcpEnum CRtpPacket::RtpPacketProcessRr(
TRtpPacketStreamParam* aStreamParam,
TRtpPacketIOParam* aExtractParam )
{
// SSRC
aStreamParam->TRTCP_RR.SSRC = Read32( iDataPtr );
iDataPtr += 4;
// fraction lost
aStreamParam->TRTCP_RR.fractionLost = iDataPtr[0];
iDataPtr++;
// cumulative number of packets lost
aStreamParam->TRTCP_RR.cumNumPacketsLost = Read24( iDataPtr );
iDataPtr += 3;
// extended highest sequence number received
aStreamParam->TRTCP_RR.seqNumReceived = Read32( iDataPtr );
iDataPtr += 4;
// interarrival jitter
aStreamParam->TRTCP_RR.arrivalJitter = Read32( iDataPtr );
iDataPtr += 4;
// last SR timestamp
aExtractParam->TRTCP_RR.lastSRTimeStamp = Read32( iDataPtr );
iDataPtr += 4;
// delay since last SR timestamp
aExtractParam->TRTCP_RR.delaySinceLSR = Read32( iDataPtr );
iDataPtr += 4;
return ERTCP_NO_ERROR;
}
// ----------------------------------------------------------------------------
// CRtpPacket::RtpPacketProcessSr()
// ----------------------------------------------------------------------------
//
TRtpRtcpEnum CRtpPacket::RtpPacketProcessSr(
TRtpPacketStreamParam* aStreamParam,
TRtpPacketIOParam* aExtractParam )
{
// SSRC
aStreamParam->TRTCP_SR.SSRC = Read32( iDataPtr );
iDataPtr += 4;
// NTP timestamp (seconds)
aExtractParam->TRTCP_SR.NTPTimeStampSec = Read32( iDataPtr );
iDataPtr += 4;
// NTP timestamp (fraction)
aExtractParam->TRTCP_SR.NTPTimeStampFrac = Read32( iDataPtr );
iDataPtr += 4;
// RTP timestamp
aExtractParam->TRTCP_SR.timeStamp = Read32( iDataPtr );
iDataPtr += 4;
// sender's packet count
aStreamParam->TRTCP_SR.numPacketsSent = Read32( iDataPtr );
iDataPtr += 4;
// sender's octet count
aStreamParam->TRTCP_SR.cumNumOctetsSent = Read32( iDataPtr );
iDataPtr += 4;
return ERTCP_NO_ERROR;
}
// ----------------------------------------------------------------------------
// CRtpPacket::RtpPacketProcessSdes()
// ----------------------------------------------------------------------------
//
TRtpRtcpEnum CRtpPacket::RtpPacketProcessSdesL(
TRtpPacketStreamParam* aStreamParam,
TRtpPacketIOParam* aExtractParam )
{
TUint8 theIndex( 0 );
TUint8 tempValue( 0 );
TInt err( KErrNone );
TUint8 sdesItems = 0;
TUint32 totalSDESSize( 0 );
// SSRC
aStreamParam->TRTCP_SDES.SSRC = Read32( iDataPtr );
iDataPtr += 4;
for ( theIndex = 0; theIndex < ERTCP_NUM_OF_SDES_ITEMS; theIndex++ )
{
aExtractParam->TRTCP_SDES.sdesItemsSize[theIndex] = 0;
}
// Read each SDES items
for ( theIndex = 0; theIndex < ERTCP_NUM_OF_SDES_ITEMS; theIndex++ )
{
if ( iDataPtr[0] != KNullTerm )
{
tempValue = iDataPtr[0];
if ( tempValue != ( theIndex + 1 ) )
{
aExtractParam->TRTCP_SDES.sdesItemsSize[theIndex] = 0;
TRAP( err, aExtractParam->TRTCP_SDES.sdesItems[theIndex] =
static_cast<TUint8*>( User::AllocL( sizeof( TUint8 ) ) ) );
if ( err )
{
return ERTCP_PACKET_ERROR;
}
*( aExtractParam->TRTCP_SDES.sdesItems[theIndex] ) = KNullTerm;
}
else
{
aExtractParam->TRTCP_SDES.sdesItemsSize[theIndex] = iDataPtr[1];
// keep track of number of SDES items
sdesItems++;
totalSDESSize +=
aExtractParam->TRTCP_SDES.sdesItemsSize[theIndex];
iDataPtr += 2;
TRAP( err, aExtractParam->TRTCP_SDES.sdesItems[theIndex] =
static_cast<TUint8*>(
User::AllocL( sizeof( TUint8 ) * (
aExtractParam->TRTCP_SDES.sdesItemsSize[theIndex] + 1 )
) ) );
if ( err )
{
return ERTCP_PACKET_ERROR;
}
Mem::Copy( aExtractParam->TRTCP_SDES.sdesItems[theIndex],
iDataPtr,
aExtractParam->TRTCP_SDES.sdesItemsSize[theIndex] );
*( aExtractParam->TRTCP_SDES.sdesItems[theIndex] +
aExtractParam->TRTCP_SDES.sdesItemsSize[theIndex] ) = KNullTerm;
iDataPtr += aExtractParam->TRTCP_SDES.sdesItemsSize[theIndex];
}
}
}
iDataPtr++; // take into account end null octet
for ( theIndex = tempValue; theIndex < ERTCP_NUM_OF_SDES_ITEMS; theIndex++ )
{
TRAP( err, aExtractParam->TRTCP_SDES.sdesItems[theIndex] =
static_cast<TUint8*>( User::AllocL( sizeof( TUint8 ) ) )
);
if ( err )
{
return ERTCP_PACKET_ERROR;
}
*( aExtractParam->TRTCP_SDES.sdesItems[theIndex] ) = KNullTerm;
}
// calculate size of padding
if ( ( sdesItems * 2 + totalSDESSize + 1 ) % 4 != 0 )
{
aExtractParam->TRTCP_SDES.paddingSize =
4 - ( sdesItems * 2 + totalSDESSize + 1 ) % 4;
}
else
{
aExtractParam->TRTCP_SDES.paddingSize = 0;
}
for ( theIndex = 0; theIndex < aExtractParam->TRTCP_SDES.paddingSize;
theIndex++ )
{
iDataPtr++;
}
return ERTCP_NO_ERROR;
}
// ---------------------------------------------------------------------------
// Return Value:
// 0 : if RTP packet has been processed OK or
// if RTCP packet has been processed OK and there are no more RTCP
// packets in this compound packet to be processed
// 1 : if RTCP packet has been processed OK and there is still RTCP
// packets in this compound packet to be processed
// -1 : if packet is invalid or some other error has occured
// ---------------------------------------------------------------------------
TRtpRtcpEnum CRtpPacket::RtpPacketProcessL( TRtpPacketStreamParam* aStreamParam,
TRtpPacketIOParam* aExtractParam )
{
TRtpRtcpEnum result( ERTCP_NO_ERROR );
// parse the packet content
switch ( iType )
{
case ERTP:
result = RtpPacketProcessRtpL( aStreamParam, aExtractParam );
return result;
// no break necessary
case ERTCP_HEADER:
result = RtpPacketProcessRtcp( aStreamParam, aExtractParam );
break;
case ERTCP_SR:
result = RtpPacketProcessSr( aStreamParam, aExtractParam );
break;
case ERTCP_RR:
result = RtpPacketProcessRr( aStreamParam, aExtractParam );
break;
case ERTCP_SDES:
result = RtpPacketProcessSdesL( aStreamParam, aExtractParam );
break;
case ERTCP_BYE:
result = RtpPacketProcessByeL( aStreamParam, aExtractParam );
break;
case ERTCP_APP:
result = RtpPacketProcessAppL( aStreamParam, aExtractParam );
break;
default:
// unknown packet type, return error
result = ERTCP_PACKET_ERROR;
break;
}
// Only RTCP packets get this far
if ( result != ERTCP_NO_ERROR )
{
return result;
}
// check if RTCP compound is ready
if ( iDataPtr == ( iData + iSize ) )
{
iDataPtr = iData;
return ERTCP_NO_ERROR;
}
else if ( iDataPtr < ( iData + iSize ) )
{
return ERTCP_PACKET_MORE;
}
else
{
return ERTCP_PACKET_ERROR;
}
}
// ---------------------------------------------------------------------------
// CRtpPacket::Write16()
// Write a 16-bit value as 2 consecutive bytes in MSB order
// Memory (at least 2 bytes) must have been allocated to pointer
// before the function is called.
// ---------------------------------------------------------------------------
void CRtpPacket::Write16( TUint8* const aPointer, TUint16 aValue )
{
// check value range (16 bits)
aPointer[0] = static_cast<TUint8>( ( aValue & 0xFF00 ) >> 8 );
aPointer[1] = static_cast<TUint8>( aValue & 0x00FF );
}
// ---------------------------------------------------------------------------
// TUint16 CRtpPacket::Read16()
// Read a 16-bit value given as 2 consecutive bytes in MSB order
// Memory (at least 2 bytes) must have been allocated to pointer
// before the function is called.
// ---------------------------------------------------------------------------
TUint16 CRtpPacket::Read16( const TUint8* const aPointer )
{
return static_cast<TUint16>( aPointer[1] + ( aPointer[0] << 8 ) );
}
// ---------------------------------------------------------------------------
// CRtpPacket::Write32()
// Write a 32-bit aValue as 4 consecutive bytes in MSB order
// Memory (at least 4 bytes) must have been allocated to aPointer
// before the function is called.
// ---------------------------------------------------------------------------
void CRtpPacket::Write32( TUint8* const aPointer, TUint32 aValue )
{
aPointer[0] = static_cast<TUint8>( ( aValue & 0xFF000000 ) >> 24 );
aPointer[1] = static_cast<TUint8>( ( aValue & 0x00FF0000 ) >> 16 );
aPointer[2] = static_cast<TUint8>( ( aValue & 0x0000FF00 ) >> 8 );
aPointer[3] = static_cast<TUint8>( aValue & 0x000000FF );
}
// ---------------------------------------------------------------------------
// TUint32 CRtpPacket::Read32()
// Read a 32-bit aValue given as 4 consecutive bytes in MSB order
// Memory (at least 4 bytes) must have been allocated to aPointer
// before the function is called.
// ---------------------------------------------------------------------------
TUint32 CRtpPacket::Read32( const TUint8* const aPointer )
{
return ( aPointer[3] +
( static_cast<TUint32>( aPointer[2] ) << 8 ) +
( static_cast<TUint32>( aPointer[1] ) << 16 ) +
( static_cast<TUint32>( aPointer[0] ) << 24 ) );
}
// ---------------------------------------------------------------------------
// CRtpPacket::Write24()
//
// ---------------------------------------------------------------------------
//
void CRtpPacket::Write24( TUint8* const aPointer, TUint32 aValue )
{
aPointer[0] = static_cast<TUint8>( ( aValue & 0xFF0000 ) >> 16 );
aPointer[1] = static_cast<TUint8>( ( aValue & 0x00FF00 ) >> 8 );
aPointer[2] = static_cast<TUint8>( aValue & 0x0000FF );
}
// ---------------------------------------------------------------------------
// TUint32 CRtpPacket::Read24()
//
// ---------------------------------------------------------------------------
//
TUint32 CRtpPacket::Read24( const TUint8 *const aPointer )
{
return ( aPointer[2] + ( static_cast<TUint32>( aPointer[1] ) << 8 ) +
( static_cast<TUint32>( aPointer[0] ) << 16 ) );
}
// End of File