in src/source/PeerConnection/Rtcp.c [140:275]
STATUS parseRtcpTwccPacket(PRtcpPacket pRtcpPacket, PTwccManager pTwccManager)
{
/*
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| FMT=15 | PT=205 | length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| SSRC of packet sender |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| SSRC of media source |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| base sequence number | packet status count |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| reference time | fb pkt. count |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| packet chunk | packet chunk |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
. .
. .
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| packet chunk | recv delta | recv delta |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
. .
. .
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| recv delta | recv delta | zero padding |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
STATUS retStatus = STATUS_SUCCESS;
INT32 packetsRemaining;
UINT16 baseSeqNum, packetStatusCount, packetSeqNum;
UINT32 chunkOffset, recvOffset;
UINT8 statusSymbol;
UINT32 packetChunk;
INT16 recvDelta;
UINT32 statuses;
UINT32 i;
UINT64 referenceTime;
CHK(pTwccManager != NULL && pRtcpPacket != NULL, STATUS_NULL_ARG);
baseSeqNum = getUnalignedInt16BigEndian(pRtcpPacket->payload + 8);
packetStatusCount = TWCC_PACKET_STATUS_COUNT(pRtcpPacket->payload);
referenceTime = (pRtcpPacket->payload[12] << 16) | (pRtcpPacket->payload[13] << 8) | (pRtcpPacket->payload[14] & 0xff);
referenceTime = KVS_CONVERT_TIMESCALE(referenceTime * 64, MILLISECONDS_PER_SECOND, HUNDREDS_OF_NANOS_IN_A_SECOND);
// TODO: handle lost twcc report packets
packetsRemaining = packetStatusCount;
chunkOffset = 16;
while (packetsRemaining > 0 && chunkOffset < pRtcpPacket->payloadLength) {
packetChunk = getUnalignedInt16BigEndian(pRtcpPacket->payload + chunkOffset);
if (IS_TWCC_RUNLEN(packetChunk)) {
packetsRemaining -= TWCC_RUNLEN_GET(packetChunk);
} else {
packetsRemaining -= MIN(TWCC_STATUSVECTOR_COUNT(packetChunk), packetsRemaining);
}
chunkOffset += TWCC_FB_PACKETCHUNK_SIZE;
}
recvOffset = chunkOffset;
chunkOffset = 16;
packetSeqNum = baseSeqNum;
packetsRemaining = packetStatusCount;
while (packetsRemaining > 0) {
packetChunk = getUnalignedInt16BigEndian(pRtcpPacket->payload + chunkOffset);
statusSymbol = TWCC_RUNLEN_STATUS_SYMBOL(packetChunk);
if (IS_TWCC_RUNLEN(packetChunk)) {
for (i = 0; i < TWCC_RUNLEN_GET(packetChunk); i++) {
recvDelta = MIN_INT16;
switch (statusSymbol) {
case TWCC_STATUS_SYMBOL_SMALLDELTA:
recvDelta = (INT16) pRtcpPacket->payload[recvOffset];
recvOffset++;
break;
case TWCC_STATUS_SYMBOL_LARGEDELTA:
recvDelta = getUnalignedInt16BigEndian(pRtcpPacket->payload + recvOffset);
recvOffset += 2;
break;
case TWCC_STATUS_SYMBOL_NOTRECEIVED:
DLOGS("runLength packetSeqNum %u not received %lu", packetSeqNum, referenceTime);
pTwccManager->twccPacketBySeqNum[packetSeqNum].remoteTimeKvs = TWCC_PACKET_LOST_TIME;
pTwccManager->lastReportedSeqNum = packetSeqNum;
break;
default:
DLOGD("runLength unhandled statusSymbol %u", statusSymbol);
}
if (recvDelta != MIN_INT16) {
referenceTime += KVS_CONVERT_TIMESCALE(recvDelta, TWCC_TICKS_PER_SECOND, HUNDREDS_OF_NANOS_IN_A_SECOND);
DLOGS("runLength packetSeqNum %u received %lu", packetSeqNum, referenceTime);
pTwccManager->twccPacketBySeqNum[packetSeqNum].remoteTimeKvs = referenceTime;
pTwccManager->lastReportedSeqNum = packetSeqNum;
}
packetSeqNum++;
packetsRemaining--;
}
} else {
statuses = MIN(TWCC_STATUSVECTOR_COUNT(packetChunk), packetsRemaining);
for (i = 0; i < statuses; i++) {
statusSymbol = TWCC_STATUSVECTOR_STATUS(packetChunk, i);
recvDelta = MIN_INT16;
switch (statusSymbol) {
case TWCC_STATUS_SYMBOL_SMALLDELTA:
recvDelta = (INT16) pRtcpPacket->payload[recvOffset];
recvOffset++;
break;
case TWCC_STATUS_SYMBOL_LARGEDELTA:
recvDelta = getUnalignedInt16BigEndian(pRtcpPacket->payload + recvOffset);
recvOffset += 2;
break;
case TWCC_STATUS_SYMBOL_NOTRECEIVED:
DLOGS("statusVector packetSeqNum %u not received %lu", packetSeqNum, referenceTime);
pTwccManager->twccPacketBySeqNum[packetSeqNum].remoteTimeKvs = TWCC_PACKET_LOST_TIME;
pTwccManager->lastReportedSeqNum = packetSeqNum;
break;
default:
DLOGD("statusVector unhandled statusSymbol %u", statusSymbol);
}
if (recvDelta != MIN_INT16) {
referenceTime += KVS_CONVERT_TIMESCALE(recvDelta, TWCC_TICKS_PER_SECOND, HUNDREDS_OF_NANOS_IN_A_SECOND);
DLOGS("statusVector packetSeqNum %u received %lu", packetSeqNum, referenceTime);
pTwccManager->twccPacketBySeqNum[packetSeqNum].remoteTimeKvs = referenceTime;
pTwccManager->lastReportedSeqNum = packetSeqNum;
}
packetSeqNum++;
packetsRemaining--;
}
}
chunkOffset += TWCC_FB_PACKETCHUNK_SIZE;
}
CleanUp:
CHK_LOG_ERR(retStatus);
return retStatus;
}