 /*
 *
 * @APPLE_LICENSE_HEADER_START@
 *
 * Copyright (c) 1999-2008 Apple Inc.  All Rights Reserved.
 *
 * This file contains Original Code and/or Modifications of Original Code
 * as defined in and that are subject to the Apple Public Source License
 * Version 2.0 (the 'License'). You may not use this file except in
 * compliance with the License. Please obtain a copy of the License at
 * http://www.opensource.apple.com/apsl/ and read it before using this
 * file.
 * 
 * The 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>
#include "SafeStdLib.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
    virtual Bool16 ParseReport(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
    };
};

class RTCPSenderReportPacket : public RTCPReceiverPacket
{
public:
	Bool16 ParseReport(UInt8* inPacketBuffer, UInt32 inPacketLength);
	SInt64 GetNTPTimeStamp()
	{
		UInt32* fieldPtr = (UInt32*)&fReceiverPacketBuffer[kSRPacketNTPTimeStampMSW];
		SInt64 timestamp = ntohl(*fieldPtr);
		fieldPtr = (UInt32*)&fReceiverPacketBuffer[kSRPacketNTPTimeStampLSW];
		return (timestamp << 32) | ntohl(*fieldPtr);
	}
	UInt32 GetRTPTimeStamp()
	{
		UInt32* fieldPtr = (UInt32*)&fReceiverPacketBuffer[kSRPacketRTPTimeStamp];
		return ntohl(*fieldPtr);
	}
protected:
    enum
    {
        kRTCPSRPacketSenderInfoInBytes = 20,
		kSRPacketNTPTimeStampMSW = 8,
		kSRPacketNTPTimeStampLSW = 12,
		kSRPacketRTPTimeStamp = 16
    };
};


/**************  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()
{
    UInt32* fieldPtr = (UInt32*)&fReceiverPacketBuffer[kPacketLengthOffset];
    UInt32 field = ntohl(*fieldPtr);
    return (UInt16) (field & kPacketLengthMask);
}

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

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_
