/* * * @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); } }