 /*
 *
 * @APPLE_LICENSE_HEADER_START@
 *
 * Copyright (c) 1999-2001 Apple Computer, Inc.  All Rights Reserved. The
 * contents of this file constitute Original Code as defined in and are
 * subject to the Apple Public Source License Version 1.2 (the 'License').
 * You may not use this file except in compliance with the License.  Please
 * obtain a copy of the License at http://www.apple.com/publicsource and
 * read it before using this file.
 *
 * This Original Code and all software distributed under the License are
 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.  Please
 * see the License for the specific language governing rights and
 * limitations under the License.
 *
 *
 * @APPLE_LICENSE_HEADER_END@
 *
 */
/*
	File:		RTCPPacket.h

	Contains:  	RTCPReceiverPacket de-packetizing classes


*/

//#define DEBUG_RTCP_PACKETS 1


#ifndef _RTCPPACKET_H_
#define _RTCPPACKET_H_

#include <stdlib.h>

#ifndef __Win32__
#include <sys/types.h>
#include <netinet/in.h>
#endif

#include "OSHeaders.h"

class RTCPPacket 
{
public:

	// Packet types
	enum
	{
		kReceiverPacketType 	= 201,	//UInt32
		kSDESPacketType 		= 202,	//UInt32
		kAPPPacketType  		= 204	//UInt32
	};
	

	RTCPPacket() : fReceiverPacketBuffer(NULL) {}
	virtual ~RTCPPacket() {}

	//Call this before any accessor method. Returns true if successful, false otherwise
	Bool16 ParsePacket(UInt8* inPacketBuffer, UInt32 inPacketLen);

	inline int GetVersion();
	inline Bool16 GetHasPadding();
	inline int GetReportCount();
	inline UInt8 GetPacketType();
	inline UInt16 GetPacketLength();	//in 32-bit words
	inline UInt32 GetPacketSSRC();
	inline SInt16 GetHeader();
	UInt8* GetPacketBuffer() { return fReceiverPacketBuffer; }
	
	Bool16 IsValidPacket();
	
	virtual void Dump();

	enum
	{
		kRTCPPacketSizeInBytes = 8,		//All are UInt32s
		kRTCPHeaderSizeInBytes = 4
	};
		
protected:
	
	UInt8* fReceiverPacketBuffer;
	
	enum
	{
		kVersionOffset = 0,
			kVersionMask = 0xC0000000UL,
			kVersionShift = 30,
		kHasPaddingOffset = 0,
			kHasPaddingMask = 0x20000000UL,
		kReportCountOffset = 0,
			kReportCountMask = 0x1F000000UL,
			kReportCountShift = 24,
		kPacketTypeOffset = 0,
			kPacketTypeMask = 0x00FF0000UL,
			kPacketTypeShift = 16,
		kPacketLengthOffset = 0,
			kPacketLengthMask = 0x0000FFFFUL,
		kPacketSourceIDOffset = 4,	//packet sender SSRC
		kPacketSourceIDSize = 4,	//
		kSupportedRTCPVersion = 2
	};

};




class SourceDescriptionPacket : public RTCPPacket

{

public:
	
	SourceDescriptionPacket() : RTCPPacket() {}
	
	Bool16 ParseSourceDescription(UInt8* inPacketBuffer, UInt32 inPacketLength)
							{ return ParsePacket(inPacketBuffer, inPacketLength); }

private:	
};




class RTCPReceiverPacket  : public RTCPPacket
{
public:

	RTCPReceiverPacket() : RTCPPacket(), fRTCPReceiverReportArray(NULL) {}

	//Call this before any accessor method. Returns true if successful, false otherwise
	Bool16 ParseReceiverReport(UInt8* inPacketBuffer, UInt32 inPacketLength);

	inline UInt32 GetReportSourceID(int inReportNum);
	 UInt8 GetFractionLostPackets(int inReportNum);
	 UInt32 GetTotalLostPackets(int inReportNum);
	inline UInt32 GetHighestSeqNumReceived(int inReportNum);
	inline UInt32 GetJitter(int inReportNum);
	inline UInt32 GetLastSenderReportTime(int inReportNum);
	inline UInt32 GetLastSenderReportDelay(int inReportNum);	//expressed in units of 1/65536 seconds

	UInt32 GetCumulativeFractionLostPackets();
	UInt32 GetCumulativeTotalLostPackets();
	UInt32 GetCumulativeJitter();

	Bool16 IsValidPacket();
	
	virtual void Dump(); //Override
	
protected:
	inline int RecordOffset(int inReportNum);

	UInt8* fRTCPReceiverReportArray;	//points into fReceiverPacketBuffer

	enum
	{
		kReportBlockOffsetSizeInBytes = 24,		//All are UInt32s

		kReportBlockOffset = kPacketSourceIDOffset + kPacketSourceIDSize,
	
		kReportSourceIDOffset = 0,	//SSRC for this report
		kFractionLostOffset = 4,
			kFractionLostMask = 0xFF000000UL,
			kFractionLostShift = 24,
		kTotalLostPacketsOffset = 4,
			kTotalLostPacketsMask = 0x00FFFFFFUL,
		kHighestSeqNumReceivedOffset = 8,
		kJitterOffset = 12,
		kLastSenderReportOffset = 16,
		kLastSenderReportDelayOffset = 20
	};

};

/**************  RTCPPacket  inlines **************/
inline int RTCPPacket::GetVersion()
{
	UInt32* theVersionPtr = (UInt32*)&fReceiverPacketBuffer[kVersionOffset];
	UInt32 theVersion = ntohl(*theVersionPtr);
	return (int) ((theVersion  & kVersionMask) >> kVersionShift);
}

inline Bool16 RTCPPacket::GetHasPadding()
{
	UInt32* theHasPaddingPtr = (UInt32*)&fReceiverPacketBuffer[kHasPaddingOffset];
	UInt32 theHasPadding = ntohl(*theHasPaddingPtr);
	return (Bool16) (theHasPadding & kHasPaddingMask);
}

inline int RTCPPacket::GetReportCount()
{
	UInt32* theReportCountPtr = (UInt32*)&fReceiverPacketBuffer[kReportCountOffset];
	UInt32 theReportCount = ntohl(*theReportCountPtr);
	return (int) ((theReportCount & kReportCountMask) >> kReportCountShift);
}

inline UInt8 RTCPPacket::GetPacketType()
{
	UInt32* thePacketTypePtr = (UInt32*)&fReceiverPacketBuffer[kPacketTypeOffset];
	UInt32 thePacketType = ntohl(*thePacketTypePtr);
	return (UInt8) ((thePacketType & kPacketTypeMask) >> kPacketTypeShift);
}

inline UInt16 RTCPPacket::GetPacketLength()
{
	return (UInt16) ( ntohl(*(UInt32*)&fReceiverPacketBuffer[kPacketLengthOffset]) & kPacketLengthMask);
}

inline UInt32 RTCPPacket::GetPacketSSRC()
{
	return (UInt32) ntohl(*(UInt32*)&fReceiverPacketBuffer[kPacketSourceIDOffset]) ;
}

inline SInt16 RTCPPacket::GetHeader(){ return (SInt16) ntohs(*(SInt16*)&fReceiverPacketBuffer[0]) ;}

/**************  RTCPReceiverPacket  inlines **************/
inline int RTCPReceiverPacket::RecordOffset(int inReportNum) 
{
	return inReportNum*kReportBlockOffsetSizeInBytes;
}	


inline UInt32 RTCPReceiverPacket::GetReportSourceID(int inReportNum)
{
	return (UInt32) ntohl(*(UInt32*)&fRTCPReceiverReportArray[this->RecordOffset(inReportNum)+kReportSourceIDOffset]) ;
}

inline UInt8 RTCPReceiverPacket::GetFractionLostPackets(int inReportNum)
{
	return (UInt8) ( (ntohl(*(UInt32*)&fRTCPReceiverReportArray[this->RecordOffset(inReportNum)+kFractionLostOffset]) & kFractionLostMask) >> kFractionLostShift );
}


inline UInt32 RTCPReceiverPacket::GetTotalLostPackets(int inReportNum)
{
	return (ntohl(*(UInt32*)&fRTCPReceiverReportArray[this->RecordOffset(inReportNum)+kTotalLostPacketsOffset]) & kTotalLostPacketsMask );
}


inline UInt32 RTCPReceiverPacket::GetHighestSeqNumReceived(int inReportNum)
{
	return (UInt32) ntohl(*(UInt32*)&fRTCPReceiverReportArray[this->RecordOffset(inReportNum)+kHighestSeqNumReceivedOffset]) ;
}

inline UInt32 RTCPReceiverPacket::GetJitter(int inReportNum)
{
	return (UInt32) ntohl(*(UInt32*)&fRTCPReceiverReportArray[this->RecordOffset(inReportNum)+kJitterOffset]) ;
}


inline UInt32 RTCPReceiverPacket::GetLastSenderReportTime(int inReportNum)
{
	return (UInt32) ntohl(*(UInt32*)&fRTCPReceiverReportArray[this->RecordOffset(inReportNum)+kLastSenderReportOffset]) ;
}


inline UInt32 RTCPReceiverPacket::GetLastSenderReportDelay(int inReportNum)
{
	return (UInt32) ntohl(*(UInt32*)&fRTCPReceiverReportArray[this->RecordOffset(inReportNum)+kLastSenderReportDelayOffset]) ;
}


/*
Receiver Report
---------------
 0                   1                   2                   3
 0 0 0 1 1 1 1 1
 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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|V=2|P|    RC   |   PT=RR=201   |             length            | header
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                     SSRC of packet sender                     |
+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|                 SSRC_1 (SSRC of first source)                 | report
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ block
| fraction lost |       cumulative number of packets lost       |   1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|           extended highest sequence number received           |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                      interarrival jitter                      |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                         last SR (LSR)                         |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                   delay since last SR (DLSR)                  |
+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|                 SSRC_2 (SSRC of second source)                | report
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ block
:                               ...                             :   2
+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|                  profile-specific extensions                  |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+



*/

#endif //_RTCPPACKET_H_
