Add even more of the source

This should be about everything needed to build so far?
This commit is contained in:
Darren VanBuren 2017-03-07 17:14:16 -08:00
parent af3619d4fa
commit 849723c9cf
547 changed files with 149239 additions and 0 deletions

View file

@ -0,0 +1,657 @@
/*
*
* @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: RTCPAPPNADUPacket.cpp
Contains: RTCPAPPNADUPacket de-packetizing classes
*/
#include "RTCPAPPNADUPacket.h"
#include "MyAssert.h"
#include "OS.h"
#include "OSMemory.h"
#include "StrPtrLen.h"
/* RTCPNaduPacket
data: One or more of the following data format blocks may appear
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|V=2|P| subtype | PT=APP=204 | length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| SSRC/CSRC |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| name (ASCII) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ <-------- data block
| SSRC |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Playout Delay | NSN |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Reserved | NUN | Free Buffer Space (FBS) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
char RTCPNaduPacket::sRTCPTestBuffer[];
RTCPNaduPacket::RTCPNaduPacket(Bool16 debug = false):
RTCPAPPPacket(debug),
fNaduDataBuffer(NULL),
fNumBlocks(0)
{
}
void RTCPNaduPacket::GetTestPacket(StrPtrLen* resultPtr)
{
/*
Compound test packet
lengths are 32 bit words, include header, are minus 1
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|V=2|P| RC | PT=RR=201 | length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|V=2|P| subtype | PT=SDES=202 | length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|V=2|P| subtype | PT=APP=204 | length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| SSRC/CSRC |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| name (ASCII) | PSS0
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+----app specific data PSS0
| SSRC |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Playout Delay | NSN |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Reserved | NUN | Free Buffer Space (FBS) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ----app data may repeat
// rtcp common header
typedef struct {
unsigned int version:2; // protocol version
unsigned int p:1; // padding flag
unsigned int count:5; // varies by packet type
unsigned int pt:8; // RTCP packet type
u_int16 length; // pkt len in words, w/o this word can be 0
} rtcp_common_t;
// rtcp compound packet starts with rtcp rr header
// rr data may be empty or not
// nadu app header follows rr header and data if any
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
#if 1 //full receiver report with SDES and Nadu
UInt32 *theWriterStart = (UInt32*)sRTCPTestBuffer;
UInt32 *theWriter = (UInt32*)sRTCPTestBuffer;
*(theWriter++) = htonl(0x81c90007); // 1 RR packet header, full report
*(theWriter++) = htonl(0x2935F2D6); // 1 Sender SSRC = 691401430
*(theWriter++) = htonl(0x6078CE22); // 1 SSRC_1 = 1618529826
*(theWriter++) = htonl(0x01000001); // fraction lost | cumulative num packets lost 1% , 1 packet
*(theWriter++) = htonl(0x0000361A); // extended highest seq number received = 13850
*(theWriter++) = htonl(0x00C7ED4D); // interarrival jitter = 13102413
*(theWriter++) = htonl(0x00000000); // LSR last sender report = 0
*(theWriter++) = htonl(0x04625238); // Delay since last SR (DLSR) = 73552440 (garbage)
*(theWriter++) = htonl(0x81ca0005); // 1 SDES packet header,
*(theWriter++) = htonl(0x2935F2D6); // 1 Sender SSRC = 691401430
*(theWriter++) = htonl(0x010A5344); // 1 CNAME = 01, len=10, "SD"
*(theWriter++) = htonl(0x45532043); // 1 CNAME = "ES C"
*(theWriter++) = htonl(0x4e414d45); // 1 CNAME = "NAME"
*(theWriter++) = htonl(0x00000000); // NULL item = end of list + 32bit padding
*(theWriter++) = htonl(0x80CC0000); // 1 APP packet header, needs len -> assigned beow
UInt32 *appPacketLenStart = theWriter;
*(theWriter++) = htonl(FOUR_CHARS_TO_INT('S', 'S', 'R', 'C')); //nadu ssrc
*(theWriter++) = htonl(FOUR_CHARS_TO_INT('P', 'S', 'S', '0')); //nadu app packet name
// first (typically only) ssrc block
*(theWriter++) = htonl(0x423A35C7); //ssrc = 1111111111
*(theWriter++) = htonl(0x2B6756CE); //delay | nsn = 11111 | 22222
*(theWriter++) = htonl(0xFFFFAD9C); //nun | fbs= 31 | 44444
// optional 2nd or more ssrc blocks
*(theWriter++) = htonl(0x84746B8E); //ssrc = 222222222
*(theWriter++) = htonl(0x2B6756CE); //delay | nsn = 11111 | 22222
*(theWriter++) = htonl(0xFFFFAD9C); //nun | fbs= 31 | 44444
UInt16 *packetLenOffsetPtr = &( (UInt16*)theWriterStart)[29];
UInt16 packetLenInWords = htons( ((UInt32*)theWriter - (UInt32*)appPacketLenStart) ) ;
*packetLenOffsetPtr = packetLenInWords;
qtss_printf("packetLenInWords =%lu\n", ntohs(packetLenInWords));
UInt32 len = (char*)theWriter - (char*)theWriterStart;
if (resultPtr)
resultPtr->Set(sRTCPTestBuffer, len);
#endif
#if 0 //full receiver report with Nadu
UInt32 *theWriterStart = (UInt32*)sRTCPTestBuffer;
UInt32 *theWriter = (UInt32*)sRTCPTestBuffer;
*(theWriter++) = htonl(0x80c90007); // 1 RR packet header, empty len is ok but could be a full report
*(theWriter++) = htonl(0x2935F2D6); // 1 SSRC = 691401430
*(theWriter++) = htonl(0x6078CE22); // 1 SSRC_1 = 1618529826
*(theWriter++) = htonl(0x01000001); // fraction lost | cumulative num packets lost 1% , 1 packet
*(theWriter++) = htonl(0x0000361A); // extended highest seq number received = 13850
*(theWriter++) = htonl(0x00C7ED4D); // interarrival jitter = 13102413
*(theWriter++) = htonl(0x00000000); // LSR last sender report = 0
*(theWriter++) = htonl(0x04625238); // Delay since last SR (DLSR) = 73552440 (garbage)
*(theWriter++) = htonl(0x80CC0000); // 1 APP packet header, needs len -> assigned beow
UInt32 *appPacketLenStart = theWriter;
*(theWriter++) = htonl(FOUR_CHARS_TO_INT('S', 'S', 'R', 'C')); //nadu ssrc
*(theWriter++) = htonl(FOUR_CHARS_TO_INT('P', 'S', 'S', '0')); //nadu app packet name
// first (typically only) ssrc block
*(theWriter++) = htonl(0x423A35C7); //ssrc = 1111111111
*(theWriter++) = htonl(0x2B6756CE); //delay | nsn = 11111 | 22222
*(theWriter++) = htonl(0xFFFFAD9C); //nun | fbs= 31 | 44444
// optional 2nd or more ssrc blocks
*(theWriter++) = htonl(0x84746B8E); //ssrc = 222222222
*(theWriter++) = htonl(0x2B6756CE); //delay | nsn = 11111 | 22222
*(theWriter++) = htonl(0xFFFFAD9C); //nun | fbs= 31 | 44444
UInt16 *packetLenOffsetPtr = &( (UInt16*)theWriterStart)[17];
UInt16 packetLenInWords = htons( (UInt32*)theWriter - (UInt32*)appPacketLenStart) ;
*packetLenOffsetPtr = packetLenInWords;
UInt32 len = (char*)theWriter - (char*)theWriterStart;
if (resultPtr)
resultPtr->Set(sRTCPTestBuffer, len);
#endif
#if 0 //empty receiver report with NADU
UInt32 *theWriterStart = (UInt32*)sRTCPTestBuffer;
UInt32 *theWriter = (UInt32*)sRTCPTestBuffer;
*(theWriter++) = htonl(0x80c90000); // 1 RR packet header, empty len is ok but could be a full report
*(theWriter++) = htonl(0x80CC0000); // 1 APP packet header, needs len -> assigned beow
UInt32 *appPacketLenStart = theWriter;
*(theWriter++) = htonl(FOUR_CHARS_TO_INT('S', 'S', 'R', 'C')); //nadu ssrc
*(theWriter++) = htonl(FOUR_CHARS_TO_INT('P', 'S', 'S', '0')); //nadu app packet name
// first (typically only) ssrc block
*(theWriter++) = htonl(0x423A35C7); //ssrc = 1111111111
*(theWriter++) = htonl(0x2B6756CE); //delay | nsn = 11111 | 22222
*(theWriter++) = htonl(0xFFFFAD9C); //nun | fbs= 31 | 44444
// optional 2nd or more ssrc blocks
*(theWriter++) = htonl(0x84746B8E); //ssrc = 222222222
*(theWriter++) = htonl(0x2B6756CE); //delay | nsn = 11111 | 22222
*(theWriter++) = htonl(0xFFFFAD9C); //nun | fbs= 31 | 44444
UInt16 *packetLenOffsetPtr = &( (UInt16*)theWriterStart)[3];
UInt16 packetLenInWords = htons( (UInt32*)theWriter - (UInt32*)appPacketLenStart) ;
*packetLenOffsetPtr = packetLenInWords;
UInt32 len = (char*)theWriter - (char*)theWriterStart;
if (resultPtr)
resultPtr->Set(sRTCPTestBuffer, len);
#endif
/*
sample run of the test packet below:
----------------------------------------
RTPStream::TestRTCPPackets received packet inPacketPtr.Ptr=0xf0080568 inPacketPtr.len =20
testing RTCPNaduPacket using packet inPacketPtr.Ptr=0xe2c38 inPacketPtr.len =40
>recv sess=1: RTCP RR recv_sec=6.812 type=video size=40 H_vers=2, H_pad=0, H_rprt_count=0, H_type=201, H_length=0, H_ssrc=-2134114296
>recv sess=1: RTCP APP recv_sec=6.813 type=video size=36 H_vers=2, H_pad=0, H_rprt_count=0, H_type=204, H_length=8, H_ssrc=1397969475
NADU Packet
Block Index = 0 (h_ssrc = 1111111111, h_playoutdelay = 11111, h_sequence_num = 22222, h_nun_unit_num = 31, h_fbs_free_buf = 44444)
Block Index = 1 (h_ssrc = 2222222222, h_playoutdelay = 11111, h_sequence_num = 22222, h_nun_unit_num = 31, h_fbs_free_buf = 44444)
Dumping Nadu List (list size = 3 record count=48)
-------------------------------------------------------------
NADU Record: list_index = 2 list_recordID = 48
Block Index = 0 (h_ssrc = 1111111111, h_playoutdelay = 11111, h_sequence_num = 22222, h_nun_unit_num = 31, h_fbs_free_buf = 44444)
Block Index = 1 (h_ssrc = 2222222222, h_playoutdelay = 11111, h_sequence_num = 22222, h_nun_unit_num = 31, h_fbs_free_buf = 44444)
NADU Record: list_index = 1 list_recordID = 47
Block Index = 0 (h_ssrc = 1111111111, h_playoutdelay = 11111, h_sequence_num = 22222, h_nun_unit_num = 31, h_fbs_free_buf = 44444)
Block Index = 1 (h_ssrc = 2222222222, h_playoutdelay = 11111, h_sequence_num = 22222, h_nun_unit_num = 31, h_fbs_free_buf = 44444)
NADU Record: list_index = 0 list_recordID = 46
Block Index = 0 (h_ssrc = 1111111111, h_playoutdelay = 11111, h_sequence_num = 22222, h_nun_unit_num = 31, h_fbs_free_buf = 44444)
Block Index = 1 (h_ssrc = 2222222222, h_playoutdelay = 11111, h_sequence_num = 22222, h_nun_unit_num = 31, h_fbs_free_buf = 44444)
*/
}
// use if you don't know what kind of packet this is
Bool16 RTCPNaduPacket::ParseNaduPacket(UInt8* inPacketBuffer, UInt32 inPacketLength)
{
if (!this->ParseAPPPacket(inPacketBuffer, inPacketLength))
return false;
if (this->GetAppPacketName() != RTCPNaduPacket::kNaduPacketName)
return false;
return true;
}
Bool16 RTCPNaduPacket::ParseAPPData(UInt8* inPacketBuffer, UInt32 inPacketLength)
{
if (!this->ParseNaduPacket(inPacketBuffer, inPacketLength) )
return false;
UInt32 *naduDataBuffer = (UInt32 *) (this->GetPacketBuffer()+kNaduDataOffset);
int wordsLen = this->GetPacketLength() - 2;
if (wordsLen < 3) // min is 3
return false;
if (0 !=(wordsLen % 3))// blocks are 3x32bits so there is a bad block somewhere.
return false;
fNumBlocks = wordsLen / 3;
if (0 == fNumBlocks)
return false;
if (fNumBlocks > 100) // too many
return false;
fNaduDataBuffer = naduDataBuffer;
if (0) //testing
this->DumpNaduPacket();
return true;
}
void RTCPNaduPacket::DumpNaduPacket()
{
char printName[5];
(void) this->GetAppPacketName(printName, sizeof(printName));
qtss_printf(" H_app_packet_name = %s, ", printName );
qtss_printf("\n");
SInt32 count = 0;
for (; count < fNumBlocks ; count ++)
{
UInt32 ssrc = this->GetSSRC(count);
UInt32 ssrcIndex = this->GetSSRCBlockIndex(ssrc);
UInt16 playoutDelay = this->GetPlayOutDelay(count);
UInt16 nsn = this->GetNSN(count);
UInt16 nun = this->GetNUN(count);
UInt16 fbs = this->GetFBS(count);
qtss_printf(" ");
qtss_printf("RTCP APP NADU Report[%"_U32BITARG_"] ", ssrcIndex);
qtss_printf("h_ssrc = %"_U32BITARG_, ssrc);
qtss_printf(", h_playoutdelay = %u", playoutDelay);
qtss_printf(", h_sequence_num = %u", nsn);
qtss_printf(", h_nun_unit_num = %u", nun);
qtss_printf(", h_fbs_free_buf = %u", fbs);
qtss_printf("\n");
}
}
SInt32 RTCPNaduPacket::GetSSRCBlockIndex(UInt32 inSSRC)
{
UInt32 *blockBuffer = NULL;
SInt32 count = 0;
UInt32 ssrc = 0;
if (NULL == fNaduDataBuffer)
return -1;
for (; count < fNumBlocks ; count ++)
{
blockBuffer = fNaduDataBuffer + (count * 3);
ssrc = (UInt32) ntohl(*(UInt32*)&blockBuffer[kOffsetNaduSSRC]);
if (ssrc == inSSRC)
return count;
}
return -1;
}
UInt32 RTCPNaduPacket::GetSSRC(SInt32 index)
{
if (index < 0)
return 0;
if (NULL == fNaduDataBuffer)
return 0;
if (index >= fNumBlocks)
return 0;
UInt32 *blockBufferPtr = fNaduDataBuffer + (index * 3);
UInt32 ssrc = (UInt32) ntohl(*(UInt32*)&blockBufferPtr[kOffsetNaduSSRC]);
return ssrc;
}
UInt16 RTCPNaduPacket::GetPlayOutDelay(SInt32 index)
{
if (index < 0)
return 0;
if (NULL == fNaduDataBuffer)
return 0;
if (index >= fNumBlocks)
return 0;
UInt32 *blockBufferPtr = fNaduDataBuffer + (index * 3);
UInt16 delay = (UInt16) ( ( ntohl(*(UInt32*)&blockBufferPtr[kOffsetNaduPlayoutDelay]) & kPlayoutMask) >> 16);
return delay;
}
UInt16 RTCPNaduPacket::GetNSN(SInt32 index)
{
if (index < 0)
return 0;
if (NULL == fNaduDataBuffer)
return 0;
if (index >= fNumBlocks)
return 0;
UInt32 *blockBufferPtr = fNaduDataBuffer + (index * 3);
UInt16 nsn = (UInt16) ( ntohl(blockBufferPtr[kOffsetNSN]) & kNSNMask );
return nsn;
}
UInt16 RTCPNaduPacket::GetNUN(SInt32 index)
{
if (index < 0)
return 0;
if (NULL == fNaduDataBuffer)
return 0;
if (index >= fNumBlocks)
return 0;
UInt32 *blockBufferPtr = fNaduDataBuffer + (index * 3);
UInt16 nun = (UInt16) ((ntohl(blockBufferPtr[kOffsetNUN]) & kNUNMask) >> 16);
return nun;
}
UInt16 RTCPNaduPacket::GetFBS(SInt32 index)
{
if (index < 0)
return 0;
if (NULL == fNaduDataBuffer)
return 0;
if (index >= fNumBlocks)
return 0;
UInt32 *blockBufferPtr = fNaduDataBuffer + (index * 3);
UInt16 fbs = (UInt16) ntohl(blockBufferPtr[kOffsetFBS]) & kFBSMask;
return fbs;
}
void RTCPNaduPacket::Dump()
{
this->DumpNaduPacket();
}
/* class NaduReport */
NaduReport::NaduReport(UInt8* inPacketBuffer, UInt32 inPacketLength, UInt32 id)
{
fPacketBuffer = NEW UInt8[inPacketLength+1];
fPacketBuffer[inPacketLength] = 0;
fLength = inPacketLength;
::memcpy(fPacketBuffer, inPacketBuffer, inPacketLength);
fNaduPacket.ParseAPPData(fPacketBuffer, inPacketLength);
fid = id;
}
/* class NaduList */
void NaduList::Initialize(UInt32 listSize)
{
fNaduReportList = NEW NaduReport *[listSize];
::memset( (void *) fNaduReportList, 0, sizeof(NaduReport*) * listSize); //initialize ptr array with 0.
fListSize = listSize;
}
NaduReport* NaduList::GetReport(UInt32 id)
{
if (NULL == fNaduReportList)
return NULL;
NaduReport *result = fNaduReportList[this->IDtoIndex(id)];
if (result && result->getID() == id)
return result;
return NULL;
}
UInt32 NaduList::GetReportIndex(UInt32 id)
{
if (NULL == fNaduReportList)
return 0;
UInt32 index = this->IDtoIndex(id);
NaduReport *result = fNaduReportList[index];
if (result && result->getID() == id)
return index;
return 0;
}
NaduReport* NaduList::GetLastReport()
{
if (NULL == fNaduReportList || fcurrentIndexCount == 0)
return NULL;
UInt32 index = this->IDtoIndex(fcurrentIndexCount);
return fNaduReportList[index];
}
NaduReport* NaduList::GetPreviousReport(NaduReport* theReport)
{
if (NULL == theReport)
return NULL;
return this->GetReport(theReport->getID() - 1);
}
NaduReport* NaduList::GetNextReport(NaduReport* theReport)
{
if (NULL == theReport)
return NULL;
return this->GetReport(theReport->getID() + 1);
}
NaduReport* NaduList::GetEarliestReport()
{
if ( fcurrentIndexCount > fListSize)
return fNaduReportList[fcurrentIndexCount % fListSize];
return fNaduReportList[0];
}
Bool16 NaduList::AddReport(UInt8* inPacketBuffer, UInt32 inPacketLength, UInt32 *outID)
{
if (NULL == fNaduReportList)
return false;
UInt32 resultID = ++fcurrentIndexCount;
UInt32 index =this->IDtoIndex(fcurrentIndexCount);
if (fNaduReportList[index] != 0)
delete fNaduReportList[index];
fNaduReportList[index] = NEW NaduReport(inPacketBuffer,inPacketLength, resultID);
if (outID)
*outID = resultID;
return true;
}
UInt32 NaduList::LastReportedFreeBuffSizeBytes()
{
NaduReport* currentReportPtr = this->GetLastReport();
if (NULL == currentReportPtr)
return 0;
RTCPNaduPacket *theNADUPacketData = currentReportPtr->GetNaduPacket();
if (NULL == theNADUPacketData)
return 0;
return ((UInt32) theNADUPacketData->GetFBS(0)) * 64; //64 byte blocks are in the report
}
UInt32 NaduList::LastReportedTimeDelayMilli()
{
NaduReport* currentReportPtr = this->GetLastReport();
if (NULL == currentReportPtr)
return 0;
RTCPNaduPacket *theNADUPacketData = currentReportPtr->GetNaduPacket();
if (NULL == theNADUPacketData)
return 0;
return theNADUPacketData->GetPlayOutDelay(0);
}
UInt16 NaduList::GetLastReportedNSN()
{
NaduReport* currentReportPtr = this->GetLastReport();
if (NULL == currentReportPtr)
return 0;
RTCPNaduPacket *theNADUPacketData = currentReportPtr->GetNaduPacket();
if (NULL == theNADUPacketData)
return 0;
return theNADUPacketData->GetNSN(0);
}
void NaduList::DumpList()
{
qtss_printf("\nDumping Nadu List (list size = %"_U32BITARG_" record count=%"_U32BITARG_")\n",fListSize, fcurrentIndexCount);
qtss_printf("-------------------------------------------------------------\n");
NaduReport* lastReportPtr = this->GetLastReport();
NaduReport* earliestReportPtr = this->GetEarliestReport();
UInt32 thisID = 0;
UInt32 stopID = 0;
if (earliestReportPtr)
stopID = earliestReportPtr->getID();
while (lastReportPtr)
{
thisID = lastReportPtr->getID();
qtss_printf("NADU Record: list_index = %"_U32BITARG_" list_recordID = %"_U32BITARG_"\n", this->GetReportIndex(thisID), thisID);
lastReportPtr->GetNaduPacket()->Dump();
if (thisID == stopID)
break;
thisID --;
lastReportPtr = this->GetReport(thisID);
}
}

View file

@ -0,0 +1,240 @@
/*
*
* @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: RTCPAPPNADUPacket.h
Contains: RTCPAPPNADUPacket de-packetizing class
*/
#ifndef _RTCPAPPNADUPACKET_H_
#define _RTCPAPPNADUPACKET_H_
#include "RTCPAPPPacket.h"
#include "StrPtrLen.h"
class RTCPNaduPacket : public RTCPAPPPacket
{
public:
RTCPNaduPacket(Bool16 debug);
virtual ~RTCPNaduPacket() {}
//Call this before any accessor method. Returns true if successful, false otherwise
virtual Bool16 ParseAPPData(UInt8* inPacketBuffer, UInt32 inPacketLength);
// Call to parse if you don't know what kind of packet this is
Bool16 ParseNaduPacket(UInt8* inPacketBuffer, UInt32 inPacketLength);
UInt32 GetNumReportBlocks() { return fNumBlocks; };
SInt32 GetSSRCBlockIndex(UInt32 inSSRC);
UInt32 GetSSRC(SInt32 index);
UInt16 GetPlayOutDelay(SInt32 index);
UInt16 GetNSN(SInt32 index);
UInt16 GetNUN(SInt32 index);
UInt16 GetFBS(SInt32 index);
void DumpNaduPacket();
static void GetTestPacket(StrPtrLen* resultPtr);
virtual void Dump(); //Override
enum
{
kNaduDataOffset = 12,
//32 bit word offsets
kOffsetNaduSSRC = 0, //SSRC for this report
kOffsetNaduPlayoutDelay = 1,
kOffsetNSN = 1,
kOffsetNUN = 2,
kOffsetFBS = 2,
kPlayoutMask = 0xFFFF0000UL,
kNSNMask = 0x0000FFFFUL,
kNUNMask = 0x001F0000UL,
kFBSMask = 0x0000FFFFUL,
kReservedPlayoutDelayValue = 0xFFFF,
kMaximumReportableFreeBufferSpace = (0xFFFF * 64) //the maximum amount of free buffer space reportable in bytes
};
enum //The 4 character name in the APP packet
{
kNaduPacketName = FOUR_CHARS_TO_INT('P', 'S', 'S', '0') //QTSS
};
enum
{
kSupportedNaduPacketVersion = 0
};
private:
void ParseAndStore();
UInt32* fNaduDataBuffer;
SInt32 fNumBlocks;
static char sRTCPTestBuffer[256];
};
/*
3GPP TS 26.234 V6.4.0 (2005-06)
6.6 APP: Application-defined RTCP 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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|V=2|P| subtype | PT=APP=204 | length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| SSRC/CSRC |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| name (ASCII) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| application-dependent data |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
For rate adaptation the name and subtype fields must be set to the following values:
name: The NADU APP data format is detected through the name "PSS0", i.e. 0x50535330 and the subtype.
subtype: This field shall be set to 0 for the NADU format.
length: The number of 32 bit words Ð1, as defined in RFC 3550 [9]. This means that the field will be 2+3*N, where N is the number of sources reported on. The length field will typically be 5, i.e. 24 bytes packets. application-dependent
data: One or more of the following data format blocks (as described in Figure 4) can be included in the application-dependent data location of the APP packet. The APP packets length field is used to detect how many blocks of data are present. The block shall be sent for the SSRCs for which there are a report block, part of either a Receiver Report or a Sender Report, included in the RTCP compound packet. An NADU APP packet shall not contain any other data format than the one described in figure 4 below.
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| SSRC |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Playout Delay | NSN |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Reserved | NUN | Free Buffer Space (FBS) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Figure 4: Data format block for NADU reporting
SSRC: The SSRC of the media stream the buffered packets belong to.
Playout delay (16 bits): The difference between the scheduled playout time of the next ADU to be decoded and the time of sending the NADU APP packet, as measured by the media playout clock, expressed in milliseconds. The client may
choose not to indicate this value by using the reserved value (Ox FFFF). In case of an empty buffer, the playout delay is not defined and the client should also use the reserved value 0xFFFF for this field. The playout delay allows the server to have a more precise value of the amount of time before the client will underflow. The playout delay shall be computed until the actual media playout (i.e., audio playback or video display).
NSN (16 bits): The RTP sequence number of the next ADU to be decoded for the SSRC reported on. In the case where the buffer does not contain any packets for this SSRC, the next not yet received sequence number shall be reported, i.e.
an NSN value that is one larger than the least significant 16 bits of the RTCP SR or RR report block's "extended highest sequence number received".
NUN (5 bits): The unit number (within the RTP packet) of the next ADU to be decoded. The first unit in a packet has a unit number equal to zero. The unit number is incremented by one for each ADU in an RTP packet. In the case of an
audio codec, an ADU is defined as an audio frame. In the case of H.264 (AVC), an ADU is defined as a NAL unit. In the case of H.263 and MPEG4 Visual Simple Profile, each packet carries a single ADU and the NUN field shall be thus
set to zero. Future additions of media encoding or transports capable of having more than one ADU in each RTP payload shall define what shall be counted as an ADU for this format.
FBS (16 bit): The amount of free buffer space available in the client at the time of reporting. The reported free buffer space shall all be part of the buffer space that has been reported as available for adaptation by the 3GPP-Adaptation RTSP header, see clause 5.3.2.2. The amount of free buffer space are reported in number of complete 64 byte blocks, thus allowing for up to 4194304 bytes to be reported as free. If more is available, it shall be reported as the maximal amount available, i.e. 4194304 with a field value 0xffff.
Reserved (11 bits): These bits are not used and shall be set to 0 and shall be ignored by the receiver.
*/
class NaduReport
{
public:
NaduReport(UInt8* inPacketBuffer, UInt32 inPacketLength, UInt32 id);
~NaduReport() { delete fPacketBuffer; }
UInt8* getBuffer() { return fPacketBuffer; }
UInt32 getLength() { return fLength; }
UInt32 getID() { return fid; }
RTCPNaduPacket * GetNaduPacket(){ return &fNaduPacket; }
UInt8* fPacketBuffer;
UInt32 fLength;
RTCPNaduPacket fNaduPacket;
UInt32 fid;
};
// Keep track of the last listSize nadu reports and access them as needed.
// DumpList prints each report while walking backward from the most recent.
class NaduList
{
public:
NaduList(): fNaduReportList(NULL), fcurrentIndexCount(0), fListSize(0) {};
~NaduList() {
for (int i = 0; i < fListSize; i++) {
if (fNaduReportList[i] != 0) {
delete fNaduReportList[i];
fNaduReportList[i] = 0;
}
}
delete [] fNaduReportList;
}
void Initialize(UInt32 listSize = 3);
Bool16 AddReport(UInt8* inPacketBuffer, UInt32 inPacketLength, UInt32 *outID);
NaduReport* GetReport(UInt32 id);
NaduReport* GetLastReport();
NaduReport* GetEarliestReport();
NaduReport* GetPreviousReport(NaduReport* theReport);
NaduReport* GetNextReport(NaduReport* theReport);
UInt32 LastReportedFreeBuffSizeBytes();
UInt32 LastReportedTimeDelayMilli();
UInt16 GetLastReportedNSN();
void DumpList();
private:
UInt32 GetReportIndex(UInt32 id);
UInt32 IDtoIndex (UInt32 id) { return (id -1) % fListSize; }
NaduReport** fNaduReportList;
UInt32 fcurrentIndexCount;
UInt32 fListSize;
};
#endif //_RTCPAPPNADUPACKET_H_

View file

@ -0,0 +1,87 @@
/*
*
* @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: RTCPAPPPacket.cpp
Contains: RTCPAPPPacket de-packetizing classes
*/
#include "RTCPAPPPacket.h"
#include "MyAssert.h"
#include "OS.h"
#include "OSMemory.h"
#include "ResizeableStringFormatter.h"
RTCPAPPPacket::RTCPAPPPacket(Bool16 debug) :
fRTCPAPPDataBuffer(NULL),
fAPPDataBufferSize(0),
mDumpArray(NULL),
mDumpArrayStrDeleter(NULL),
fDumpReport(),
fDebug(debug)
{
if (fDebug)
{
mDumpArray = NEW char[kmDumpArraySize];
mDumpArray[0] = '\0';
mDumpArrayStrDeleter.Set(mDumpArray);
}
}
void RTCPAPPPacket::Dump()//Override
{
RTCPPacket::Dump();
fDumpReport.PutTerminator();
qtss_printf("%s\n", fDumpReport.GetBufPtr());
fDumpReport.Reset();
}
Bool16 RTCPAPPPacket::ParseAPPPacketHeader(UInt8* inPacketBuffer, UInt32 inPacketLength)
{
if (inPacketLength < kRTCPPacketSizeInBytes + kRTCPAPPHeaderSizeInBytes)
return false;
return true;
}
Bool16 RTCPAPPPacket::ParseAPPPacket(UInt8* inPacketBuffer, UInt32 inPacketLength)
{
if (false == this->ParsePacket(inPacketBuffer, inPacketLength) ) // base class
return false;
return this->ParseAPPPacketHeader(inPacketBuffer, inPacketLength);
}

View file

@ -0,0 +1,126 @@
/*
*
* @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: RTCPAPPPacket.h
Contains: RTCPAPPPacket de-packetizing classes
*/
#ifndef _RTCPAPPPACKET_H_
#define _RTCPAPPPACKET_H_
#include "RTCPPacket.h"
#include "StrPtrLen.h"
#include "ResizeableStringFormatter.h"
#define APPEND_TO_DUMP_ARRAY(f, v) {if (fDebug && mDumpArray != NULL) { (void)::snprintf(mDumpArray,kmDumpArraySize, f, v); fDumpReport.Put(mDumpArray); } }
class RTCPAPPPacket : public RTCPPacket
{
public:
RTCPAPPPacket(Bool16 debug = false);
virtual ~RTCPAPPPacket() {};
virtual void Dump();
virtual Bool16 ParseAPPPacket(UInt8* inPacketBuffer, UInt32 inPacketLength); //default app header check
virtual Bool16 ParseAPPData(UInt8* inPacketBuffer, UInt32 inPacketLength) { return false; }; //derived class implements
inline FourCharCode GetAppPacketName(char *outName = NULL, UInt32 len = 0);
inline UInt32 GetAppPacketSSRC();
UInt8* fRTCPAPPDataBuffer; //points into RTCPPacket::fReceiverPacketBuffer should be set past the app header
UInt32 fAPPDataBufferSize;
enum
{
kAppSSRCOffset = 4,
kAppNameOffset = 8, //byte offset to four char App identifier //All are UInt32
kRTCPAPPHeaderSizeInBytes = 4, //
kmDumpArraySize = 1024
};
char* mDumpArray;
StrPtrLenDel mDumpArrayStrDeleter;
ResizeableStringFormatter fDumpReport;
Bool16 fDebug;
private:
virtual Bool16 ParseAPPPacketHeader(UInt8* inPacketBuffer, UInt32 inPacketLength);
};
/**************** RTCPAPPPacket inlines *******************************/
inline FourCharCode RTCPAPPPacket::GetAppPacketName(char *outName, UInt32 len)
{
UInt32 packetName = (UInt32) (*(UInt32*)&(GetPacketBuffer()[kAppNameOffset]) ) ;
if (outName)
{ if (len > 4)
{ *((UInt32*)outName) = packetName;
outName[4] = 0;
}
else if (len > 0)
outName[0] = 0;
}
return ntohl(packetName);
}
inline UInt32 RTCPAPPPacket::GetAppPacketSSRC()
{
return (UInt32) ntohl(*(UInt32*)&(GetPacketBuffer()[kAppSSRCOffset]) ) ;
}
/*
6.6 APP: Application-defined RTCP 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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|V=2|P| subtype | PT=APP=204 | length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| SSRC/CSRC |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| name (ASCII) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| application-dependent data |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
#endif //_RTCPAPPPACKET_H_

View file

@ -0,0 +1,316 @@
/*
*
* @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: RTCPAPPQTSSPacket.cpp
Contains: RTCPAPPQTSSPacket de-packetizing classes
*/
#include "RTCPAPPQTSSPacket.h"
#include "MyAssert.h"
#include "OS.h"
#include "OSMemory.h"
RTCPCompressedQTSSPacket::RTCPCompressedQTSSPacket(Bool16 debug) :
RTCPAPPPacket(debug),
fReceiverBitRate(0),
fAverageLateMilliseconds(0),
fPercentPacketsLost(0),
fAverageBufferDelayMilliseconds(0),
fIsGettingBetter(false),
fIsGettingWorse(false),
fNumEyes(0),
fNumEyesActive(0),
fNumEyesPaused(0),
fOverbufferWindowSize(kUInt32_Max),
//Proposed - are these there yet?
fTotalPacketsReceived(0),
fTotalPacketsDropped(0),
fTotalPacketsLost(0),
fClientBufferFill(0),
fFrameRate(0),
fExpectedFrameRate(0),
fAudioDryCount(0)
{
}
// use if you don't know what kind of packet this is
Bool16 RTCPCompressedQTSSPacket::ParseCompressedQTSSPacket(UInt8* inPacketBuffer, UInt32 inPacketLength)
{
if (!this->ParseAPPPacket(inPacketBuffer, inPacketLength))
return false;
if (this->GetAppPacketName() != RTCPCompressedQTSSPacket::kCompressedQTSSPacketName)
return false;
if (inPacketLength < kQTSSDataOffset)
return false;
//figure out how many 32-bit words remain in the buffer
UInt32 theMaxDataLen = inPacketLength - kQTSSDataOffset;
theMaxDataLen /= 4;
//if the number of 32 bit words reported in the packet is greater than the theoretical limit,
//return an error
if (this->GetQTSSPacketLength() > theMaxDataLen)
return false;
if (this->GetQTSSPacketVersion() != kSupportedCompressedQTSSVersion)
return false;
if (this->GetReportCount() > 0)
return false;
return true;
}
// You know the packet type and just want to parse it now
Bool16 RTCPCompressedQTSSPacket::ParseAPPData(UInt8* inPacketBuffer, UInt32 inPacketLength)
{
if ( !this->ParseCompressedQTSSPacket(inPacketBuffer, inPacketLength) )
return false;
APPEND_TO_DUMP_ARRAY("%s","\n RTCP APP QTSS Report ");
char printName[5];
(void) this->GetAppPacketName(printName, sizeof(printName));
APPEND_TO_DUMP_ARRAY("H_app_packet_name = %s, ", printName );
APPEND_TO_DUMP_ARRAY("H_ssrc = %"_U32BITARG_", ", this->GetPacketSSRC());
APPEND_TO_DUMP_ARRAY("H_src_ID = %"_U32BITARG_", ", this->GetQTSSReportSourceID());
APPEND_TO_DUMP_ARRAY("H_vers=%d, ", this->GetQTSSPacketVersion());
APPEND_TO_DUMP_ARRAY("H_packt_len=%d", this->GetQTSSPacketLength());
UInt8* qtssDataBuffer = this->GetPacketBuffer()+kQTSSDataOffset;
//packet length is given in words
UInt32 bytesRemaining = this->GetQTSSPacketLength() * 4;
while ( bytesRemaining >= 4 ) //items must be at least 32 bits
{
// DMS - There is no guarentee that qtssDataBuffer will be 4 byte aligned, because
// individual APP packet fields can be 6 bytes or 4 bytes or 8 bytes. So we have to
// use the 4-byte align protection functions. Sparc and MIPS processors will crash otherwise
UInt32 theHeader = ntohl(OS::GetUInt32FromMemory((UInt32*)&qtssDataBuffer[kQTSSItemTypeOffset]));
UInt16 itemType = (UInt16)((theHeader & kQTSSItemTypeMask) >> kQTSSItemTypeShift);
UInt8 itemVersion = (UInt8)((theHeader & kQTSSItemVersionMask) >> kQTSSItemVersionShift);
UInt8 itemLengthInBytes = (UInt8)(theHeader & kQTSSItemLengthMask);
APPEND_TO_DUMP_ARRAY("\n h_type=%.2s(", (char*)&itemType);
APPEND_TO_DUMP_ARRAY(", h_vers=%u", itemVersion);
APPEND_TO_DUMP_ARRAY(", h_size=%u", itemLengthInBytes);
qtssDataBuffer += sizeof(UInt32); //advance past the above UInt16's & UInt8's (point it at the actual item data)
//Update bytesRemaining (move it past current item)
//This itemLengthInBytes is part of the packet and could therefore be bogus.
//Make sure not to overstep the end of the buffer!
bytesRemaining -= sizeof(UInt32);
if (itemLengthInBytes > bytesRemaining)
break; //don't walk off the end of the buffer
//itemLengthInBytes = bytesRemaining;
bytesRemaining -= itemLengthInBytes;
switch (itemType)
{
case TW0_CHARS_TO_INT( 'r', 'r' ): //'rr': //'rrcv':
{
fReceiverBitRate = ntohl(OS::GetUInt32FromMemory((UInt32*)qtssDataBuffer));
qtssDataBuffer += sizeof(fReceiverBitRate);
APPEND_TO_DUMP_ARRAY(", rcvr_bit_rate=%"_U32BITARG_"", fReceiverBitRate);
}
break;
case TW0_CHARS_TO_INT('l', 't'): //'lt': //'late':
{
fAverageLateMilliseconds = ntohs(*(UInt16*)qtssDataBuffer);
qtssDataBuffer += sizeof(fAverageLateMilliseconds);
APPEND_TO_DUMP_ARRAY(", avg_late=%u", fAverageLateMilliseconds);
}
break;
case TW0_CHARS_TO_INT('l', 's'): // 'ls': //'loss':
{
fPercentPacketsLost = ntohs(*(UInt16*)qtssDataBuffer);
qtssDataBuffer += sizeof(fPercentPacketsLost);
APPEND_TO_DUMP_ARRAY(", percent_loss=%u", fPercentPacketsLost);
}
break;
case TW0_CHARS_TO_INT('d', 'l'): //'dl': //'bdly':
{
fAverageBufferDelayMilliseconds = ntohs(*(UInt16*)qtssDataBuffer);
qtssDataBuffer += sizeof(fAverageBufferDelayMilliseconds);
APPEND_TO_DUMP_ARRAY(", avg_buf_delay=%u", fAverageBufferDelayMilliseconds);
}
break;
case TW0_CHARS_TO_INT(':', ')' ): //:)
{
fIsGettingBetter = true;
APPEND_TO_DUMP_ARRAY(", quality=%s","better");
}
break;
case TW0_CHARS_TO_INT(':', '(' ): // ':(':
{
fIsGettingWorse = true;
APPEND_TO_DUMP_ARRAY(", quality=%s","worse");
}
break;
case TW0_CHARS_TO_INT(':', '|' ): // ':|':
{
fIsGettingWorse = true;
APPEND_TO_DUMP_ARRAY(", quality=%s","same");
}
break;
case TW0_CHARS_TO_INT('e', 'y' ): //'ey': //'eyes':
{
fNumEyes = ntohl(OS::GetUInt32FromMemory((UInt32*)qtssDataBuffer));
qtssDataBuffer += sizeof(fNumEyes);
APPEND_TO_DUMP_ARRAY(", eyes=%"_U32BITARG_"", fNumEyes);
if (itemLengthInBytes >= 2)
{
fNumEyesActive = ntohl(OS::GetUInt32FromMemory((UInt32*)qtssDataBuffer));
qtssDataBuffer += sizeof(fNumEyesActive);
APPEND_TO_DUMP_ARRAY(", eyes_actv=%"_U32BITARG_"", fNumEyesActive);
}
if (itemLengthInBytes >= 3)
{
fNumEyesPaused = ntohl(OS::GetUInt32FromMemory((UInt32*)qtssDataBuffer));
qtssDataBuffer += sizeof(fNumEyesPaused);
APPEND_TO_DUMP_ARRAY(", eyes_pausd=%"_U32BITARG_"", fNumEyesPaused);
}
}
break;
case TW0_CHARS_TO_INT('p', 'r' ): // 'pr': //'prcv':
{
fTotalPacketsReceived = ntohl(OS::GetUInt32FromMemory((UInt32*)qtssDataBuffer));
qtssDataBuffer += sizeof(fTotalPacketsReceived);
APPEND_TO_DUMP_ARRAY(", pckts_rcvd=%"_U32BITARG_"", fTotalPacketsReceived);
}
break;
case TW0_CHARS_TO_INT('p', 'd'): //'pd': //'pdrp':
{
fTotalPacketsDropped = ntohs(*(UInt16*)qtssDataBuffer);
qtssDataBuffer += sizeof(fTotalPacketsDropped);
APPEND_TO_DUMP_ARRAY(", pckts_drppd=%u", fTotalPacketsDropped);
}
break;
case TW0_CHARS_TO_INT('p', 'l'): //'pl': //'p???':
{
fTotalPacketsLost = ntohs(*(UInt16*)qtssDataBuffer);
qtssDataBuffer += sizeof(fTotalPacketsLost);
APPEND_TO_DUMP_ARRAY(", ttl_pckts_lost=%u", fTotalPacketsLost);
}
break;
case TW0_CHARS_TO_INT('b', 'l'): //'bl': //'bufl':
{
fClientBufferFill = ntohs(*(UInt16*)qtssDataBuffer);
qtssDataBuffer += sizeof(fClientBufferFill);
APPEND_TO_DUMP_ARRAY(", buffr_fill=%u", fClientBufferFill);
}
break;
case TW0_CHARS_TO_INT('f', 'r'): //'fr': //'frat':
{
fFrameRate = ntohs(*(UInt16*)qtssDataBuffer);
qtssDataBuffer += sizeof(fFrameRate);
APPEND_TO_DUMP_ARRAY(", frame_rate=%u", fFrameRate);
}
break;
case TW0_CHARS_TO_INT('x', 'r'): //'xr': //'xrat':
{
fExpectedFrameRate = ntohs(*(UInt16*)qtssDataBuffer);
qtssDataBuffer += sizeof(fExpectedFrameRate);
APPEND_TO_DUMP_ARRAY(", xpectd_frame_rate=%u", fExpectedFrameRate);
}
break;
case TW0_CHARS_TO_INT('d', '#'): //'d#': //'dry#':
{
fAudioDryCount = ntohs(*(UInt16*)qtssDataBuffer);
qtssDataBuffer += sizeof(fAudioDryCount);
APPEND_TO_DUMP_ARRAY(", aud_dry_count=%u", fAudioDryCount);
}
break;
case TW0_CHARS_TO_INT('o', 'b'): //'ob': // overbuffer window size
{
fOverbufferWindowSize = ntohl(OS::GetUInt32FromMemory((UInt32*)qtssDataBuffer));
qtssDataBuffer += sizeof(fOverbufferWindowSize);
APPEND_TO_DUMP_ARRAY(", ovr_buffr_windw_siz=%"_U32BITARG_"", fOverbufferWindowSize);
}
break;
default:
{
if (fDebug)
{
char s[12] = "";
qtss_sprintf(s, " [%.2s]", (char*)&itemType);
WarnV(false, "Unknown APP('QTSS') item type");
WarnV(false, s);
}
}
break;
} // switch (itemType)
APPEND_TO_DUMP_ARRAY("%s", "), ");
} //while ( bytesRemaining >= 4 )
return true;
}
void RTCPCompressedQTSSPacket::Dump()//Override
{
APPEND_TO_DUMP_ARRAY("%s", "\n");
RTCPAPPPacket::Dump();
}

View file

@ -0,0 +1,272 @@
/*
*
* @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: RTCPAPPQTSSPacket.h
Contains: RTCPAPPQTSSPacket de-packetizing classes
*/
#ifndef _RTCPAPPQTSSPACKET_H_
#define _RTCPAPPQTSSPACKET_H_
#include "RTCPAPPPacket.h"
#include "StrPtrLen.h"
/****** RTCPCompressedQTSSPacket is the packet type that the client actually sends ******/
class RTCPCompressedQTSSPacket : public RTCPAPPPacket
{
public:
RTCPCompressedQTSSPacket(Bool16 debug = false);
virtual ~RTCPCompressedQTSSPacket() {}
//Call this before any accessor method. Returns true if successful, false otherwise
virtual Bool16 ParseAPPData(UInt8* inPacketBuffer, UInt32 inPacketLength);
// Call to parse if you don't know what kind of packet this is
Bool16 ParseCompressedQTSSPacket(UInt8* inPacketBuffer, UInt32 inPacketLength);
inline UInt32 GetQTSSReportSourceID();
inline UInt16 GetQTSSPacketVersion();
inline UInt16 GetQTSSPacketLength(); //In 'UInt32's
inline UInt32 GetReceiverBitRate() {return fReceiverBitRate;}
inline UInt16 GetAverageLateMilliseconds() {return fAverageLateMilliseconds;}
inline UInt16 GetPercentPacketsLost() {return fPercentPacketsLost;}
inline UInt16 GetAverageBufferDelayMilliseconds() {return fAverageBufferDelayMilliseconds;}
inline Bool16 GetIsGettingBetter() {return fIsGettingBetter;}
inline Bool16 GetIsGettingWorse() {return fIsGettingWorse;}
inline UInt32 GetNumEyes() {return fNumEyes;}
inline UInt32 GetNumEyesActive() {return fNumEyesActive;}
inline UInt32 GetNumEyesPaused() {return fNumEyesPaused;}
inline UInt32 GetOverbufferWindowSize() {return fOverbufferWindowSize;}
//Proposed - are these there yet?
inline UInt32 GetTotalPacketReceived() {return fTotalPacketsReceived;}
inline UInt16 GetTotalPacketsDropped() {return fTotalPacketsDropped;}
inline UInt16 GetTotalPacketsLost() {return fTotalPacketsLost;}
inline UInt16 GetClientBufferFill() {return fClientBufferFill;}
inline UInt16 GetFrameRate() {return fFrameRate;}
inline UInt16 GetExpectedFrameRate() {return fExpectedFrameRate;}
inline UInt16 GetAudioDryCount() {return fAudioDryCount;}
virtual void Dump(); //Override
static void GetTestPacket(StrPtrLen* resultPtr) {}
UInt32 fReceiverBitRate;
UInt16 fAverageLateMilliseconds;
UInt16 fPercentPacketsLost;
UInt16 fAverageBufferDelayMilliseconds;
Bool16 fIsGettingBetter;
Bool16 fIsGettingWorse;
UInt32 fNumEyes;
UInt32 fNumEyesActive;
UInt32 fNumEyesPaused;
UInt32 fOverbufferWindowSize;
//Proposed - are these there yet?
UInt32 fTotalPacketsReceived;
UInt16 fTotalPacketsDropped;
UInt16 fTotalPacketsLost;
UInt16 fClientBufferFill;
UInt16 fFrameRate;
UInt16 fExpectedFrameRate;
UInt16 fAudioDryCount;
enum // QTSS App Header offsets
{
kQTSSDataOffset = 20, // in bytes from packet start
kQTSSReportSourceIDOffset = 3, //in 32 bit words SSRC for this report
kQTSSPacketVersionOffset = 4, // in 32bit words
kQTSSPacketVersionMask = 0xFFFF0000UL,
kQTSSPacketVersionShift = 16,
kQTSSPacketLengthOffset = 4, // in 32bit words
kQTSSPacketLengthMask = 0x0000FFFFUL,
};
enum // QTSS App Data Offsets
{
//Individual item offsets/masks
kQTSSItemTypeOffset = 0, //SSRC for this report
kQTSSItemTypeMask = 0xFFFF0000UL,
kQTSSItemTypeShift = 16,
kQTSSItemVersionOffset = 0,
kQTSSItemVersionMask = 0x0000FF00UL,
kQTSSItemVersionShift = 8,
kQTSSItemLengthOffset = 0,
kQTSSItemLengthMask = 0x000000FFUL,
kQTSSItemDataOffset = 4,
//version we support currently
kSupportedCompressedQTSSVersion = 0
};
enum //The 4 character name in the APP packet
{
kCompressedQTSSPacketName = FOUR_CHARS_TO_INT('Q', 'T', 'S', 'S') //QTSS
};
private:
void ParseAndStore();
};
inline UInt32 RTCPCompressedQTSSPacket::GetQTSSReportSourceID()
{
return (UInt32) ntohl( ((UInt32*)this->GetPacketBuffer())[kQTSSReportSourceIDOffset] ) ;
}
inline UInt16 RTCPCompressedQTSSPacket::GetQTSSPacketVersion()
{
UInt32 field = ((UInt32*)this->GetPacketBuffer())[kQTSSPacketVersionOffset];
UInt16 vers = (UInt16) ( ( ntohl(field) & kQTSSPacketVersionMask) >> kQTSSPacketVersionShift );
return vers;
}
inline UInt16 RTCPCompressedQTSSPacket::GetQTSSPacketLength()
{
UInt32 field = ((UInt32*)this->GetPacketBuffer())[kQTSSPacketLengthOffset];
return (UInt16) ( (UInt32) ntohl(field) & kQTSSPacketLengthMask );
}
/*
QTSS APP: QTSS Application-defined RTCP 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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|V=2|P| subtype | PT=APP=204 | length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| SSRC/CSRC |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| name (ASCII) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ <---- app data start
| SSRC/CSRC |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| version | length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| field name='ob' other | version=0 | length=4 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Over-buffer window size in bytes |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
fieldnames = rr, lt, ls, dl, :), :|, :(, ey, pr, pd, pl, bl, fr, xr, d#, ob
*/
/****** RTCPqtssPacket is apparently no longer sent by the client ******/
class RTCPqtssPacket : public RTCPAPPPacket
{
public:
RTCPqtssPacket() : RTCPAPPPacket() {}
virtual ~RTCPqtssPacket() {}
//Call this before any accessor method. Returns true if successful, false otherwise
virtual Bool16 ParseAPPData(UInt8* inPacketBuffer, UInt32 inPacketLength);
//Call this before any accessor method. Returns true if successful, false otherwise
Bool16 ParseQTSSPacket(UInt8* inPacketBuffer, UInt32 inPacketLength);
inline UInt32 GetReceiverBitRate() {return fReceiverBitRate;}
inline UInt32 GetAverageLateMilliseconds() {return fAverageLateMilliseconds;}
inline UInt32 GetPercentPacketsLost() {return fPercentPacketsLost;}
inline UInt32 GetAverageBufferDelayMilliseconds() {return fAverageBufferDelayMilliseconds;}
inline Bool16 GetIsGettingBetter() {return fIsGettingBetter;}
inline Bool16 GetIsGettingWorse() {return fIsGettingWorse;}
inline UInt32 GetNumEyes() {return fNumEyes;}
inline UInt32 GetNumEyesActive() {return fNumEyesActive;}
inline UInt32 GetNumEyesPaused() {return fNumEyesPaused;}
//Proposed - are these there yet?
inline UInt32 GetTotalPacketReceived() {return fTotalPacketsReceived;}
inline UInt32 GetTotalPacketsDropped() {return fTotalPacketsDropped;}
inline UInt32 GetClientBufferFill() {return fClientBufferFill;}
inline UInt32 GetFrameRate() {return fFrameRate;}
inline UInt32 GetExpectedFrameRate() {return fExpectedFrameRate;}
inline UInt32 GetAudioDryCount() {return fAudioDryCount;}
private:
void ParseAndStore();
UInt32 fReportSourceID;
UInt16 fAppPacketVersion;
UInt16 fAppPacketLength; //In 'UInt32's
UInt32 fReceiverBitRate;
UInt32 fAverageLateMilliseconds;
UInt32 fPercentPacketsLost;
UInt32 fAverageBufferDelayMilliseconds;
Bool16 fIsGettingBetter;
Bool16 fIsGettingWorse;
UInt32 fNumEyes;
UInt32 fNumEyesActive;
UInt32 fNumEyesPaused;
//Proposed - are these there yet?
UInt32 fTotalPacketsReceived;
UInt32 fTotalPacketsDropped;
UInt32 fClientBufferFill;
UInt32 fFrameRate;
UInt32 fExpectedFrameRate;
UInt32 fAudioDryCount;
enum
{
//Individual item offsets/masks
kQTSSItemTypeOffset = 0, //SSRC for this report
kQTSSItemVersionOffset = 4,
kQTSSItemVersionMask = 0xFFFF0000UL,
kQTSSItemVersionShift = 16,
kQTSSItemLengthOffset = 4,
kQTSSItemLengthMask = 0x0000FFFFUL,
kQTSSItemDataOffset = 8,
//version we support currently
kSupportedQTSSVersion = 0
};
};
#endif //_RTCPAPPQTSSPACKET_H_

View file

@ -0,0 +1,118 @@
/*
*
* @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: RTCPAckPacket.cpp
Contains: RTCPAckPacket de-packetizing class
*/
#include "RTCPAckPacket.h"
#include "RTCPPacket.h"
#include "MyAssert.h"
#include "OS.h"
#include "OSMemory.h"
#include "OSArrayObjectDeleter.h"
#include <stdio.h>
// use if you don't know what kind of packet this is
Bool16 RTCPAckPacket::ParseAckPacket(UInt8* inPacketBuffer, UInt32 inPacketLength)
{
if (!this->ParseAPPPacket(inPacketBuffer, inPacketLength))
return false;
if (this->GetAppPacketName() == RTCPAckPacket::kAckPacketName)
return true;
if (this->GetAppPacketName() == RTCPAckPacket::kAckPacketAlternateName)
return true;
return false;
}
Bool16 RTCPAckPacket::ParseAPPData(UInt8* inPacketBuffer, UInt32 inPacketLength)
{
if ( !this->ParseAckPacket(inPacketBuffer, inPacketLength) )
return false;
fRTCPAckBuffer = inPacketBuffer;
//
// Check whether this is an ack packet or not.
if ( (inPacketLength < kAckMaskOffset) || (!this->IsAckPacketType() ) )
return false;
Assert(inPacketLength == (UInt32)((this->GetPacketLength() * 4)) + RTCPPacket::kRTCPHeaderSizeInBytes);
fAckMaskSize = inPacketLength - kAckMaskOffset;
return true;
}
Bool16 RTCPAckPacket::IsAckPacketType()
{
// While we are moving to a new type, check for both
UInt32 theAppType = this->GetAppPacketName();
// if ( theAppType == kAckPacketAlternateName ) qtss_printf("ack\n");
// if ( theAppType == kAckPacketName ) qtss_printf("qtack\n");
return this->IsAckType(theAppType);
}
void RTCPAckPacket::Dump()
{
UInt16 theSeqNum = this->GetAckSeqNum();
UInt16 thePacketLen = this->GetPacketLength();
UInt32 theAckMaskSizeInBits = this->GetAckMaskSizeInBits();
char name[5];
name[4] = 0;
::memcpy(name, &fRTCPAckBuffer[kAppPacketTypeOffset],4);
UInt16 numBufferBytes = (UInt16) ( (7 * theAckMaskSizeInBits) + 1 );
char *maskBytesBuffer = NEW char[numBufferBytes];
OSCharArrayDeleter deleter(maskBytesBuffer);
maskBytesBuffer[0] = 0;
maskBytesBuffer[numBufferBytes -1] = 0;
for (UInt32 maskCount = 0; maskCount < theAckMaskSizeInBits; maskCount++)
{
if (this->IsNthBitEnabled(maskCount))
{
qtss_sprintf(&maskBytesBuffer[::strlen(maskBytesBuffer)],"%"_U32BITARG_", ", theSeqNum + 1 + maskCount);
}
}
Assert(::strlen(maskBytesBuffer) < numBufferBytes);
qtss_printf(" H_name=%s H_seq=%u H_len=%u mask_size=%"_U32BITARG_" seq_nums_bit_set=%s\n",
name, theSeqNum,thePacketLen,theAckMaskSizeInBits, maskBytesBuffer);
}

View file

@ -0,0 +1,151 @@
/*
*
* @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: RTCPAckPacket.h
Contains: RTCPAckPacket de-packetizing class
*/
#ifndef _RTCPACKPACKET_H_
#define _RTCPACKPACKET_H_
#include "OSHeaders.h"
#include "RTCPAPPPacket.h"
#include <stdlib.h>
#include "SafeStdLib.h"
#ifndef __Win32__
#include <netinet/in.h>
#endif
class RTCPAckPacket : public RTCPAPPPacket
{
public:
/*
RTCP app ACK packet
# bytes description
------- -----------
4 rtcp header
4 SSRC of receiver
4 app type ('qtak')
2 reserved (set to 0)
2 seqNum
*/
//
// This class is not derived from RTCPPacket as a performance optimization.
// Instead, it is assumed that the RTCP packet validation has already been
// done.
RTCPAckPacket() : fRTCPAckBuffer(NULL), fAckMaskSize(0) {}
virtual ~RTCPAckPacket() {}
// Call to parse if you don't know what kind of packet this is
// Returns true if this is an Ack packet, false otherwise.
// Assumes that inPacketBuffer is a pointer to a valid RTCP packet header.
Bool16 ParseAckPacket(UInt8* inPacketBuffer, UInt32 inPacketLength);
virtual Bool16 ParseAPPData(UInt8* inPacketBuffer, UInt32 inPacketLength);
inline UInt16 GetAckSeqNum();
inline UInt32 GetAckMaskSizeInBits() { return fAckMaskSize * 8; }
inline Bool16 IsNthBitEnabled(UInt32 inBitNumber);
inline UInt16 GetPacketLength();
void Dump();
static void GetTestPacket(StrPtrLen* resultPtr) {} //todo
enum
{
kAckPacketName = FOUR_CHARS_TO_INT('q', 't', 'a', 'k'), // 'qtak' documented Apple reliable UDP packet type
kAckPacketAlternateName = FOUR_CHARS_TO_INT('a', 'c', 'k', ' '), // 'ack ' required by QT 5 and earlier
};
private:
UInt8* fRTCPAckBuffer;
UInt32 fAckMaskSize;
Bool16 IsAckPacketType();
enum
{
kAppPacketTypeOffset = 8,
kAckSeqNumOffset = 16,
kAckMaskOffset = 20,
kPacketLengthMask = 0x0000FFFFUL,
};
inline Bool16 IsAckType(UInt32 theAppType) { return ( (theAppType == kAckPacketAlternateName) || (theAppType == kAckPacketName) );}
};
Bool16 RTCPAckPacket::IsNthBitEnabled(UInt32 inBitNumber)
{
// Don't need to do endian conversion because we're dealing with 8-bit numbers
UInt8 bitMask = 128;
return *(fRTCPAckBuffer + kAckMaskOffset + (inBitNumber >> 3)) & (bitMask >>= inBitNumber & 7);
}
UInt16 RTCPAckPacket::GetAckSeqNum()
{
return (UInt16) (ntohl(*(UInt32*)&fRTCPAckBuffer[kAckSeqNumOffset]));
}
inline UInt16 RTCPAckPacket::GetPacketLength()
{
return (UInt16) ( ntohl(*(UInt32*)fRTCPAckBuffer) & kPacketLengthMask);
}
/*
6.6 Ack Packet format
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|V=2|P| subtype | PT=APP=204 | length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| SSRC/CSRC |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| name (ASCII) = 'qtak' |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| SSRC/CSRC |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Reserved | Seq num |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Mask... |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
#endif //_RTCPAPPPACKET_H_

View file

@ -0,0 +1,158 @@
/*
*
* @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: RTCPAckPacketFmt.h
Some useful things for Generating Ack Packets
*/
#ifndef _RTCPACKPACKETFMT_H_
#define _RTCPACKPACKETFMT_H_
#include <stdlib.h>
#include <arpa/inet.h>
#include "StrPtrLen.h"
#include "OSHeaders.h"
#include "MyAssert.h"
class RTCPAckPacketFmt
{
enum {
RTP_VERSION = 2,
RTCP_SR = 200,
RTCP_RR = 201,
RTCP_SDES = 202,
RTCP_BYE = 203,
RTCP_APP = 204
};
struct RTCPAckHeader {
#if 0
//ackheader
unsigned int version:2; /* protocol version */
unsigned int p:1; /* padding flag */
unsigned int subtype:5; /* the subtype of ack */
unsigned int pt:8; /* RTCP packet type */
#endif
UInt16 ackheader;
UInt16 length; /* pkt len in words, w/o this word */
UInt32 SSRC; /* sender generating this packet */
UInt32 name; /* four ASCII chars */
UInt32 SSRC1; /* SSRC of the stream */
UInt16 reserved;
UInt16 seqNum;
};
public:
RTCPAckPacketFmt() : fBitMaskSize(0) {}
RTCPAckPacketFmt(StrPtrLen &newBuffer) : fBitMaskSize(0) { SetBuffer(newBuffer); }
RTCPAckPacketFmt(char *newBuffer, UInt32 bufLen) : fBitMaskSize(0) { SetBuffer(newBuffer, bufLen); }
//Setting the buffer resets the packet
void SetBuffer(StrPtrLen &newBuffer) { return this->SetBuffer(newBuffer.Ptr, newBuffer.Len); }
void SetBuffer(char *newBuffer, UInt32 bufLen)
{
Assert(sizeof(RTCPAckHeader) == 20);
Assert(bufLen >= sizeof(RTCPAckHeader));
fBitMaskSize = 0;
fBuf.Set(newBuffer, bufLen);
//fill in the header
RTCPAckHeader &header = *reinterpret_cast<RTCPAckHeader *>(fBuf.Ptr);
::memset(&header, 0, sizeof(header));
header.ackheader = htons(0x80CC); //(RTP_VERSION << 14) + RTCP_APP;
header.length = htons(GetPacketLen() / 4 - 1);
header.name = htonl(FOUR_CHARS_TO_INT('q', 't', 'a', 'k'));
}
void SetSSRC(UInt32 SSRC)
{
RTCPAckHeader &header = *reinterpret_cast<RTCPAckHeader *>(fBuf.Ptr);
header.SSRC = htonl(SSRC);
}
//Can handle duplicates
void SetAcks(SVector<UInt32> AckList, UInt32 serverSSRC)
{
Assert(!AckList.empty());
::qsort(AckList.begin(), AckList.size(), sizeof(UInt32), UInt32Compare);
RTCPAckHeader &header = *reinterpret_cast<RTCPAckHeader *>(fBuf.Ptr);
header.SSRC1 = htonl(serverSSRC);
header.seqNum = htons(static_cast<UInt16>(AckList.front()));
fBitMaskSize = 0;
if (AckList.front() == AckList.back()) //no mask is needed
return;
//figure out how big the mask is supposed to be
UInt32 slotsInMaskNeeded = AckList.back() - AckList.front();
fBitMaskSize = slotsInMaskNeeded % 32 == 0 ? (slotsInMaskNeeded / 32) * 4 : (slotsInMaskNeeded / 32 + 1) * 4;
header.length = htons(GetPacketLen() / 4 - 1);
Assert(fBuf.Len >= GetPacketLen());
UInt32 *mask = reinterpret_cast<UInt32 *>(fBuf.Ptr + sizeof(RTCPAckHeader));
::memset(mask, 0, fBitMaskSize);
//calculate where the bit to set is supposed to be and sets the bits
for(UInt32 i = 1; i < AckList.size(); ++i)
{
if (AckList.front() == AckList[i])
continue;
UInt32 diff = AckList[i] - (AckList.front() + 1);
UInt32 maskIndex = diff / 32;
UInt32 shiftSize = diff % 32;
mask[maskIndex] |= 0x80000000 >> shiftSize;
Assert(maskIndex * 4 < fBitMaskSize);
}
//restore big-endianess of the mask
for(UInt32 i = 0; i < fBitMaskSize / 4; ++i)
mask[i] = htonl(mask[i]);
}
//The length of packet written out
UInt32 GetPacketLen() { return sizeof(RTCPAckHeader) + fBitMaskSize; }
StrPtrLen GetBufferRemaining() { return StrPtrLen(fBuf.Ptr + GetPacketLen(), fBuf.Len - GetPacketLen()); }
StrPtrLen GetPacket() { return StrPtrLen(fBuf.Ptr, GetPacketLen()); }
private:
static int UInt32Compare(const void *left, const void *right)
{
UInt32 l = *reinterpret_cast<const UInt32 *>(left);
UInt32 r = *reinterpret_cast<const UInt32 *>(right);
return l < r ? -1 : l > r ? 1 : 0;
}
StrPtrLen fBuf;
UInt32 fBitMaskSize; // in bytes, not words
};
#endif //_RTCPACKPACKETFMT_H_

View file

@ -0,0 +1,132 @@
/*
*
* @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: RTCPAPPNADUPacketFmt.h
Some useful things for Generating a 3GPP NADU packet
*/
#ifndef _RTCPNADUPACKETFMT_H_
#define _RTCPNADUPACKETFMT_H_
#include "StrPtrLen.h"
#include "arpa/inet.h"
#include "OSHeaders.h"
#include "MyAssert.h"
class RTCPNADUPacketFmt
{
enum {
RTP_VERSION = 2,
RTCP_SR = 200,
RTCP_RR = 201,
RTCP_SDES = 202,
RTCP_BYE = 203,
RTCP_APP = 204
};
struct NADUHeader {
#if 0
//naduheader
unsigned int version:2; /* protocol version */
unsigned int p:1; /* padding flag */
unsigned int subtype:5; /* 0 */
unsigned int pt:8; /* RTCP packet type -- which should be RTCP_APP */
#endif
UInt16 naduHeader;
UInt16 length; /* packet length in words, minus 1 word */
UInt32 SSRC; /* SSRC of packet sender */
UInt32 name; /* in ASCII */
};
struct NADUBlock {
UInt32 SSRC; /* data source being reported */
UInt16 delay; /* the playout delay, in milliseconds */
UInt16 NSN; /* the RTP sequence number of the next ADU to be decoded; if the buffer is empty then the next not yet received sequence number */
UInt16 NUN; /* the unit number of the next ADU to be decoded */
UInt16 FBS; /* the free buffer space, in complete 64 byte blocks */
};
public:
RTCPNADUPacketFmt() : fNumNADUBlocks(0) {}
RTCPNADUPacketFmt(StrPtrLen &newBuffer) : fNumNADUBlocks(0) { SetBuffer(newBuffer); }
RTCPNADUPacketFmt(char *newBuffer, UInt32 bufLen) : fNumNADUBlocks(0) { SetBuffer(newBuffer, bufLen); }
//Setting the buffer resets the packet content
void SetBuffer(StrPtrLen &newBuffer) { return this->SetBuffer(newBuffer.Ptr, newBuffer.Len); }
void SetBuffer(char *newBuffer, UInt32 bufLen)
{
Assert(sizeof(NADUHeader) == 12);
Assert(sizeof(NADUBlock) == 12);
Assert(bufLen >= sizeof(NADUHeader));
fBuf.Set(newBuffer, bufLen);
fNumNADUBlocks = 0;
//fill in the header
NADUHeader &header = *reinterpret_cast<NADUHeader *>(fBuf.Ptr);
::memset(&header, 0, sizeof(header));
header.naduHeader = htons(0x80CC); //(RTP_VERSION << 14) + RTCP_APP;
header.name = htonl(FOUR_CHARS_TO_INT('P', 'S', 'S', '0'));
header.length = htons(GetPacketLen() / 4 - 1);
}
//units are in milliseconds and in bytes; use a playoutDelay of kUInt32_Max if the buffer is empty
void AddNADUBlock(UInt32 SSRC, UInt32 nextSeqNum, UInt8 nextUnitNum, UInt32 freeBufferSpace, UInt32 playoutDelay = kUInt32_Max)
{
Assert(fBuf.Len >= GetPacketLen() + sizeof(NADUBlock));
NADUBlock &nadu = *reinterpret_cast<NADUBlock *>(fBuf.Ptr + GetPacketLen());
::memset(&nadu, 0, sizeof(NADUBlock));
fNumNADUBlocks++;
reinterpret_cast<NADUHeader *>(fBuf.Ptr)->length = htons(GetPacketLen() / 4 - 1);
nadu.SSRC = htonl(SSRC);
nadu.NSN = htons(static_cast<UInt16>(nextSeqNum));
nadu.NUN = htons(nextUnitNum & 0x1F);
//Use reserved value of 0xffff for undefined
playoutDelay = MIN(0xffff, playoutDelay);
nadu.delay = htons(static_cast<UInt16>(playoutDelay));
//the free buffer space is reported in 64 bytes blocks, and maximum value is 0xffff
freeBufferSpace = MIN(0xffff, freeBufferSpace / 64);
nadu.FBS = htons(static_cast<UInt16>(freeBufferSpace));
}
void SetSSRC(UInt32 SSRC) { reinterpret_cast<NADUHeader *>(fBuf.Ptr)->SSRC = htonl(SSRC); }
//The length of packet written out
UInt32 GetPacketLen() { return sizeof(NADUHeader) + sizeof(NADUBlock) * fNumNADUBlocks; }
StrPtrLen GetBufferRemaining() { return StrPtrLen(fBuf.Ptr + GetPacketLen(), fBuf.Len - GetPacketLen()); }
StrPtrLen GetPacket() { return StrPtrLen(fBuf.Ptr, GetPacketLen()); }
private:
StrPtrLen fBuf;
UInt32 fNumNADUBlocks;
};
#endif //_RTCPNADUPACKETFMT_H_

View file

@ -0,0 +1,177 @@
/*
*
* @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.cpp
Contains: RTCPReceiverPacket de-packetizing classes
*/
#include "RTCPPacket.h"
#include "RTCPAckPacket.h"
#include "OS.h"
#include <stdio.h>
#define RTCP_PACKET_DEBUG 0
//returns true if successful, false otherwise
Bool16 RTCPPacket::ParsePacket(UInt8* inPacketBuffer, UInt32 inPacketLen)
{
if (inPacketLen < kRTCPPacketSizeInBytes)
return false;
fReceiverPacketBuffer = inPacketBuffer;
if (RTCP_PACKET_DEBUG) qtss_printf("RTCPPacket::ParsePacket first 4 bytes of packet=%x \n", ntohl( *(UInt32 *)inPacketBuffer));
//the length of this packet can be no less than the advertised length (which is
//in 32-bit words, so we must multiply) plus the size of the header (4 bytes)
if (RTCP_PACKET_DEBUG) qtss_printf("RTCPPacket::ParsePacket len=%"_U32BITARG_" min allowed=%"_U32BITARG_"\n", inPacketLen,(UInt32)((this->GetPacketLength() * 4) + kRTCPHeaderSizeInBytes));
if (inPacketLen < (UInt32)((this->GetPacketLength() * 4) + kRTCPHeaderSizeInBytes))
{ if (RTCP_PACKET_DEBUG) qtss_printf("RTCPPacket::ParsePacket invalid len=%"_U32BITARG_"\n", inPacketLen);
return false;
}
//do some basic validation on the packet
if (this->GetVersion() != kSupportedRTCPVersion)
{ if (RTCP_PACKET_DEBUG) qtss_printf("RTCPPacket::ParsePacket unsupported version\n");
return false;
}
return true;
}
void RTCPReceiverPacket::Dump()//Override
{
RTCPPacket::Dump();
qtss_printf("\n");
for (int i = 0;i<this->GetReportCount(); i++)
{
qtss_printf( " RTCP RR Report[%d] H_ssrc=%"_U32BITARG_", H_frac_lost=%d, H_tot_lost=%"_U32BITARG_", H_high_seq=%"_U32BITARG_" H_jit=%"_U32BITARG_", H_last_sr_time=%"_U32BITARG_", H_last_sr_delay=%"_U32BITARG_" \n",
i,
this->GetReportSourceID(i),
this->GetFractionLostPackets(i),
this->GetTotalLostPackets(i),
this->GetHighestSeqNumReceived(i),
this->GetJitter(i),
this->GetLastSenderReportTime(i),
this->GetLastSenderReportDelay(i) );
}
}
Bool16 RTCPReceiverPacket::ParseReport(UInt8* inPacketBuffer, UInt32 inPacketLength)
{
Bool16 ok = this->ParsePacket(inPacketBuffer, inPacketLength);
if (!ok)
return false;
fRTCPReceiverReportArray = inPacketBuffer + kRTCPPacketSizeInBytes;
//this is the maximum number of reports there could possibly be
int theMaxReports = (inPacketLength - kRTCPPacketSizeInBytes) / kReportBlockOffsetSizeInBytes;
//if the number of receiver reports is greater than the theoretical limit, return an error.
if (this->GetReportCount() > theMaxReports)
{ if (RTCP_PACKET_DEBUG) printf("RTCPReceiverPacket::ParseReport this rtcp report count=%d > max reports=%d\n",this->GetReportCount(), theMaxReports);
return false;
}
return true;
}
UInt32 RTCPReceiverPacket::GetCumulativeFractionLostPackets()
{
float avgFractionLost = 0;
for (short i = 0; i < this->GetReportCount(); i++)
{
avgFractionLost += this->GetFractionLostPackets(i);
avgFractionLost /= (i+1);
}
return (UInt32)avgFractionLost;
}
UInt32 RTCPReceiverPacket::GetCumulativeJitter()
{
float avgJitter = 0;
for (short i = 0; i < this->GetReportCount(); i++)
{
avgJitter += this->GetJitter(i);
avgJitter /= (i + 1);
}
return (UInt32)avgJitter;
}
UInt32 RTCPReceiverPacket::GetCumulativeTotalLostPackets()
{
UInt32 totalLostPackets = 0;
for (short i = 0; i < this->GetReportCount(); i++)
{
totalLostPackets += this->GetTotalLostPackets(i);
}
return totalLostPackets;
}
Bool16 RTCPSenderReportPacket::ParseReport(UInt8* inPacketBuffer, UInt32 inPacketLength)
{
Bool16 ok = this->ParsePacket(inPacketBuffer, inPacketLength);
if (!ok)
return false;
if (inPacketLength < kRTCPPacketSizeInBytes + kRTCPSRPacketSenderInfoInBytes)
return false;
fRTCPReceiverReportArray = inPacketBuffer + kRTCPPacketSizeInBytes + kRTCPSRPacketSenderInfoInBytes;
//this is the maximum number of reports there could possibly be
int theNumReports = (inPacketLength - kRTCPPacketSizeInBytes - kRTCPSRPacketSenderInfoInBytes) / kReportBlockOffsetSizeInBytes;
//if the number of receiver reports is greater than the theoretical limit, return an error.
if (this->GetReportCount() > theNumReports)
return false;
return true;
}
void RTCPPacket::Dump()
{
qtss_printf( "H_vers=%d, H_pad=%d, H_rprt_count=%d, H_type=%d, H_length=%d, H_ssrc=%"_S32BITARG_"",
this->GetVersion(),
(int)this->GetHasPadding(),
this->GetReportCount(),
(int)this->GetPacketType(),
(int)this->GetPacketLength(),
this->GetPacketSSRC() );
}

View file

@ -0,0 +1,334 @@
/*
*
* @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_

View file

@ -0,0 +1,153 @@
/*
*
* @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: RTCPRRPacket.h
Some useful things for Generating Receiver Report Packet
*/
#ifndef _RTCPRRPACKET_H_
#define _RTCPRRPACKET_H_
#include "StrPtrLen.h"
#include "arpa/inet.h"
#include "OSHeaders.h"
#include "MyAssert.h"
class RTCPRRPacket
{
enum {
RTP_VERSION = 2,
RTCP_SR = 200,
RTCP_RR = 201,
RTCP_SDES = 202,
RTCP_BYE = 203,
RTCP_APP = 204,
MAX_REPORTS = 0x1F // 5 bits
};
struct RTCPRRHeader {
#if 0
//receiver report header
unsigned int version:2; /* protocol version */
unsigned int p:1; /* padding flag */
unsigned int count:5; /* varies by packet type */
unsigned int pt:8; /* RTCP packet type */
#endif
UInt16 rrheader;
UInt16 length; /* packet length in words, minus 1 word */
UInt32 SSRC; /* SSRC of packet sender */
};
struct RTCPReportBlock {
UInt32 ssrc; /* data source being reported */
unsigned int fraction:8; /* fraction lost since last SR/RR */
int lost:24; /* cumul. no. of pkts lost (signed!) */
UInt32 last_seq; /* extended last seq. no. received */
UInt32 jitter; /* interarrival jitter */
UInt32 lsr; /* last SR packet from this source */
UInt32 dlsr; /* delay since last SR packet */
};
public:
RTCPRRPacket() : fNumReportBlocks(0) {}
RTCPRRPacket(StrPtrLen &newBuffer) : fNumReportBlocks(0) { SetBuffer(newBuffer); }
RTCPRRPacket(char *newBuffer, UInt32 bufLen) : fNumReportBlocks(0) { SetBuffer(newBuffer, bufLen); }
//Setting the buffer resets the packet content
void SetBuffer(StrPtrLen &newBuffer) { return this->SetBuffer(newBuffer.Ptr, newBuffer.Len); }
void SetBuffer(char *newBuffer, UInt32 bufLen)
{
Assert(sizeof(RTCPRRHeader) == 8);
Assert(sizeof(RTCPReportBlock) == 24);
Assert(bufLen >= sizeof(RTCPRRHeader));
fBuf.Set(newBuffer, bufLen);
fNumReportBlocks = 0;
//fill in the header
RTCPRRHeader &header = *reinterpret_cast<RTCPRRHeader *>(fBuf.Ptr);
::memset(&header, 0, sizeof(header));
header.rrheader = htons(0x80C9); //(RTP_VERSION << 14) + RTCP_RR;
header.length = htons(GetPacketLen() / 4 - 1);
}
void SetSSRC(UInt32 SSRC) { reinterpret_cast<RTCPRRHeader *>(fBuf.Ptr)->SSRC = htonl(SSRC); }
void SetCount(UInt16 count)
{
if (count > MAX_REPORTS) //5 bits
{ return;
}
UInt16 newVal = ntohs(*reinterpret_cast<UInt16 *>(fBuf.Ptr));
count <<= 8;
newVal |= count;
*reinterpret_cast<UInt16 *>(fBuf.Ptr) = htons(newVal);
}
void AddReportBlock(UInt32 SSRC, UInt8 fractionLost, SInt32 cumLostPackets, UInt32 highestSeqNum, UInt32 lsr, UInt32 dlsr)
{
Assert(fBuf.Len >= GetPacketLen() + sizeof(RTCPReportBlock));
if (fNumReportBlocks >= MAX_REPORTS)
{ return;
}
RTCPReportBlock &reportBlock = *reinterpret_cast<RTCPReportBlock *>(fBuf.Ptr + GetPacketLen());
::memset(&reportBlock, 0, sizeof(RTCPReportBlock));
reportBlock.ssrc = htonl(SSRC);
reportBlock.fraction = fractionLost;
reportBlock.last_seq = htonl(highestSeqNum);
reportBlock.lsr = htonl(lsr);
reportBlock.dlsr = htonl(dlsr);
//since the cumulative packets lost is a 24 bit signed integer, its clamped between 0x7fffff and 0x800000)
if(cumLostPackets > 0x7fffff)
reportBlock.lost = htonl(0x7fffff);
else if (cumLostPackets < static_cast<SInt32>(0xff800000))
reportBlock.lost = htonl(0x800000);
else
reportBlock.lost = htonl(cumLostPackets);
SetCount(++fNumReportBlocks);
reinterpret_cast<RTCPRRHeader *>(fBuf.Ptr)->length = htons(GetPacketLen() / 4 - 1);
}
//The length of packet written out
UInt32 GetPacketLen() { return sizeof(RTCPRRHeader) + sizeof(RTCPReportBlock) * fNumReportBlocks; }
StrPtrLen GetBufferRemaining() { return StrPtrLen(fBuf.Ptr + GetPacketLen(), fBuf.Len - GetPacketLen()); }
StrPtrLen GetPacket() { return StrPtrLen(fBuf.Ptr, GetPacketLen()); }
private:
StrPtrLen fBuf;
UInt32 fNumReportBlocks;
};
#endif //_RTCPRRPACKET_H_

View file

@ -0,0 +1,119 @@
/*
*
* @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: RTCPSRPacket.cpp
Contains: A class that writes a RTCP Sender Report
Change History (most recent first):
*/
#include <string.h>
#include "RTCPSRPacket.h"
#include "MyAssert.h"
#include "OS.h"
RTCPSRPacket::RTCPSRPacket()
{
// Write as much of the Sender Report as is possible
char theTempCName[kMaxCNameLen];
UInt32 cNameLen = RTCPSRPacket::GetACName(theTempCName);
//write the SR & SDES headers
UInt32* theSRWriter = (UInt32*)&fSenderReportBuffer;
*theSRWriter = htonl(0x80c80006);
theSRWriter += 7; //number of UInt32s in an SR.
//SDES length is the length of the CName, plus 2 32bit words, plus the 32bit word for the SSRC
*theSRWriter = htonl(0x81ca0000 + (cNameLen >> 2) + 1);
::memcpy(&fSenderReportBuffer[kSenderReportSizeInBytes], theTempCName, cNameLen);
fSenderReportSize = kSenderReportSizeInBytes + cNameLen;
/*
SERVER INFO PACKET FORMAT
struct qtss_rtcp_struct
{
RTCPHeader header;
UInt32 ssrc; // ssrc of rtcp originator
OSType name;
UInt32 senderSSRC;
SInt16 reserved;
SInt16 length; // bytes of data (atoms) / 4
// qtsi_rtcp_atom structures follow
};
*/
//
// Write the SERVER INFO APP packet
UInt32* theAckInfoWriter = (UInt32*)&fSenderReportBuffer[fSenderReportSize];
*theAckInfoWriter = htonl(0x81cc0006);
theAckInfoWriter += 2;
*(theAckInfoWriter++) = htonl(FOUR_CHARS_TO_INT('q', 't', 's', 'i')); // Ack Info APP name
theAckInfoWriter++; // leave space for the ssrc (again)
*(theAckInfoWriter++) = htonl(2); // 2 UInt32s for the 'at' field
*(theAckInfoWriter++) = htonl(FOUR_CHARS_TO_INT( 'a', 't', 0, 4 ));
fSenderReportWithServerInfoSize = (char*)(theAckInfoWriter+1) - fSenderReportBuffer;
UInt32* theByeWriter = (UInt32*)&fSenderReportBuffer[fSenderReportWithServerInfoSize];
*theByeWriter = htonl(0x81cb0001);
}
UInt32 RTCPSRPacket::GetACName(char* ioCNameBuffer)
{
static char* sCNameBase = "QTSS";
//clear out the whole buffer
::memset(ioCNameBuffer, 0, kMaxCNameLen);
//cName identifier
ioCNameBuffer[0] = 1;
//Unique cname is constructed from the base name and the current time
qtss_sprintf(&ioCNameBuffer[1], " %s%"_64BITARG_"d", sCNameBase, OS::Milliseconds() / 1000);
UInt32 cNameLen = ::strlen(ioCNameBuffer);
//2nd byte of CName should be length
ioCNameBuffer[1] = (UInt8) (cNameLen - 2);//don't count indicator or length byte
// This function assumes that the cName is the only item in this SDES chunk
// (see RTP rfc for details).
// The RFC says that the item (the cName) should not be NULL terminated, but
// the chunk *must* be NULL terminated. And padded to a 32-bit boundary.
//
// qtss_sprintf already put a NULL terminator in the cName buffer. So all we have to
// do is pad out to the boundary.
cNameLen += 1; //add on the NULL character
UInt32 paddedLength = cNameLen + (4 - (cNameLen % 4));
// Pad, and zero out as we pad.
for (; cNameLen < paddedLength; cNameLen++)
ioCNameBuffer[cNameLen] = '\0';
Assert((cNameLen % 4) == 0);
return cNameLen;
}

View file

@ -0,0 +1,163 @@
/*
*
* @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: RTCPSRPacket.h
Contains: A class that writes a RTCP Sender Report
Change History (most recent first):
*/
#ifndef __RTCP_SR_PACKET__
#define __RTCP_SR_PACKET__
#include "OSHeaders.h"
#include "OS.h"
#include "MyAssert.h"
#ifndef __Win32__
#include <netinet/in.h> //definition of htonl
#endif
class RTCPSRPacket
{
public:
enum
{
kSRPacketType = 200, //UInt32
kByePacketType = 203
};
RTCPSRPacket();
~RTCPSRPacket() {}
// ACCESSORS
void* GetSRPacket() { return &fSenderReportBuffer[0]; }
UInt32 GetSRPacketLen() { return fSenderReportWithServerInfoSize; }
UInt32 GetSRWithByePacketLen() { return fSenderReportWithServerInfoSize + kByeSizeInBytes; }
void* GetServerInfoPacket() { return &fSenderReportBuffer[fSenderReportSize]; }
UInt32 GetServerInfoPacketLen() { return kServerInfoSizeInBytes; }
//
// MODIFIERS
//
// FOR SR
inline void SetSSRC(UInt32 inSSRC);
inline void SetClientSSRC(UInt32 inClientSSRC);
inline void SetNTPTimestamp(SInt64 inNTPTimestamp);
inline void SetRTPTimestamp(UInt32 inRTPTimestamp);
inline void SetPacketCount(UInt32 inPacketCount);
inline void SetByteCount(UInt32 inByteCount);
//
// FOR SERVER INFO APP PACKET
inline void SetAckTimeout(UInt32 inAckTimeoutInMsec);
//RTCP support requires generating unique CNames for each session.
//This function generates a proper cName and returns its length. The buffer
//passed in must be at least kMaxCNameLen
enum
{
kMaxCNameLen = 60 //Uint32
};
static UInt32 GetACName(char* ioCNameBuffer);
private:
enum
{
kSenderReportSizeInBytes = 36,
kServerInfoSizeInBytes = 28,
kByeSizeInBytes = 8
};
char fSenderReportBuffer[kSenderReportSizeInBytes + kMaxCNameLen + kServerInfoSizeInBytes + kByeSizeInBytes];
UInt32 fSenderReportSize;
UInt32 fSenderReportWithServerInfoSize;
};
inline void RTCPSRPacket::SetSSRC(UInt32 inSSRC)
{
// Set SSRC in SR
((UInt32*)&fSenderReportBuffer)[1] = htonl(inSSRC);
// Set SSRC in SDES
((UInt32*)&fSenderReportBuffer)[8] = htonl(inSSRC);
// Set SSRC in SERVER INFO
Assert((fSenderReportSize & 3) == 0);
((UInt32*)&fSenderReportBuffer)[(fSenderReportSize >> 2) + 1] = htonl(inSSRC);
// Set SSRC in BYE
Assert((fSenderReportWithServerInfoSize & 3) == 0);
((UInt32*)&fSenderReportBuffer)[(fSenderReportWithServerInfoSize >> 2) + 1] = htonl(inSSRC);
}
inline void RTCPSRPacket::SetClientSSRC(UInt32 inClientSSRC)
{
//
// Set Client SSRC in SERVER INFO
((UInt32*)&fSenderReportBuffer)[(fSenderReportSize >> 2) + 3] = htonl(inClientSSRC);
}
inline void RTCPSRPacket::SetNTPTimestamp(SInt64 inNTPTimestamp)
{
#if ALLOW_NON_WORD_ALIGN_ACCESS
((SInt64*)&fSenderReportBuffer)[1] = OS::HostToNetworkSInt64(inNTPTimestamp);
#else
SInt64 temp = OS::HostToNetworkSInt64(inNTPTimestamp);
::memcpy(&((SInt64*)&fSenderReportBuffer)[1], &temp, sizeof(temp));
#endif
}
inline void RTCPSRPacket::SetRTPTimestamp(UInt32 inRTPTimestamp)
{
((UInt32*)&fSenderReportBuffer)[4] = htonl(inRTPTimestamp);
}
inline void RTCPSRPacket::SetPacketCount(UInt32 inPacketCount)
{
((UInt32*)&fSenderReportBuffer)[5] = htonl(inPacketCount);
}
inline void RTCPSRPacket::SetByteCount(UInt32 inByteCount)
{
((UInt32*)&fSenderReportBuffer)[6] = htonl(inByteCount);
}
inline void RTCPSRPacket::SetAckTimeout(UInt32 inAckTimeoutInMsec)
{
((UInt32*)&fSenderReportBuffer)[(fSenderReportWithServerInfoSize >> 2) - 1] = htonl(inAckTimeoutInMsec);
}
#endif //__RTCP_SR_PACKET__