in libraries/amazon/amazon-kinesis-video-streams-webrtc-sdk-c/patch/src/source/PeerConnection/Retransmitter.c [44:166]
STATUS resendPacketOnNack(PRtcpPacket pRtcpPacket, PKvsPeerConnection pKvsPeerConnection)
{
ENTERS();
STATUS retStatus = STATUS_SUCCESS;
UINT32 senderSsrc = 0, receiverSsrc = 0;
UINT32 filledLen = 0, validIndexListLen = 0;
PKvsRtpTransceiver pSenderTranceiver = NULL;
UINT64 item, index;
STATUS tmpStatus = STATUS_SUCCESS;
PRtpPacket pRtxRtpPacket = NULL;
PRetransmitter pRetransmitter = NULL;
// stats
UINT32 retransmittedPacketsSent = 0, retransmittedBytesSent = 0, nackCount = 0;
PRtpPacketRef pRtpPacketRef = NULL;
BOOL isRtpPacketRefValid = TRUE;
PBYTE rawPacket = NULL;
UINT32 packetLen = 0;
UINT32 allocSize = 0;
CHK(pKvsPeerConnection != NULL && pRtcpPacket != NULL, STATUS_NULL_ARG);
CHK_STATUS(rtcpNackListGet(pRtcpPacket->payload, pRtcpPacket->payloadLength, &senderSsrc, &receiverSsrc, NULL, &filledLen));
tmpStatus = findTransceiverBySsrc(pKvsPeerConnection, &pSenderTranceiver, receiverSsrc);
if (STATUS_NOT_FOUND == tmpStatus) {
CHK_STATUS_ERR(findTransceiverBySsrc(pKvsPeerConnection, &pSenderTranceiver, senderSsrc), STATUS_RTCP_INPUT_SSRC_INVALID,
"Receiving NACK for non existing ssrcs: senderSsrc %lu receiverSsrc %lu", senderSsrc, receiverSsrc);
}
CHK_STATUS(tmpStatus);
pRetransmitter = pSenderTranceiver->sender.retransmitter;
// TODO it is not very clear from the spec whether nackCount is number of packets received or number of rtp packets lost reported in nack packets
nackCount++;
CHK_ERR(pRetransmitter != NULL, STATUS_INVALID_OPERATION,
"Sender re-transmitter is not created successfully for an existing ssrcs: senderSsrc %lu receiverSsrc %lu", senderSsrc, receiverSsrc);
filledLen = pRetransmitter->seqNumListLen;
CHK_STATUS(rtcpNackListGet(pRtcpPacket->payload, pRtcpPacket->payloadLength, &senderSsrc, &receiverSsrc, pRetransmitter->sequenceNumberList,
&filledLen));
validIndexListLen = pRetransmitter->validIndexListLen;
CHK_STATUS(rtpRollingBufferGetValidSeqIndexList(pSenderTranceiver->sender.packetBuffer, pRetransmitter->sequenceNumberList, filledLen,
pRetransmitter->validIndexList, &validIndexListLen));
for (index = 0; index < validIndexListLen; index++) {
retStatus = rollingBufferExtractData(pSenderTranceiver->sender.packetBuffer->pRollingBuffer, pRetransmitter->validIndexList[index], &item);
pRtpPacketRef = (PRtpPacketRef) item;
CHK(retStatus == STATUS_SUCCESS, retStatus);
isRtpPacketRefValid = TRUE;
if (pRtpPacketRef == NULL) {
isRtpPacketRefValid = FALSE;
} else {
if (pRtpPacketRef->onRtpResend != NULL) {
uint8_t *pData = NULL;
size_t uLen = 0;
if (pRtpPacketRef->onRtpResend(&pData, &uLen, pRtpPacketRef->pAppData) != 0) {
isRtpPacketRefValid = FALSE;
} else {
/* TODO: Should we check refAddr too? */
}
}
}
if (isRtpPacketRefValid == TRUE) {
allocSize = pRtpPacketRef->rawPacketHdrLength + pRtpPacketRef->refLength + SRTP_AUTH_TAG_OVERHEAD;
rawPacket = (PBYTE) MEMALLOC(allocSize);
CHK(rawPacket != NULL, STATUS_NOT_ENOUGH_MEMORY);
MEMCPY(rawPacket, pRtpPacketRef->pRawPacketHdr, pRtpPacketRef->rawPacketHdrLength);
MEMCPY(rawPacket + pRtpPacketRef->rawPacketHdrLength, pRtpPacketRef->refAddr + pRtpPacketRef->refOffset, pRtpPacketRef->refLength);
packetLen = pRtpPacketRef->rawPacketHdrLength + pRtpPacketRef->refLength;
if (pSenderTranceiver->sender.payloadType == pSenderTranceiver->sender.rtxPayloadType) {
CHK_STATUS(encryptRtpPacket(pKvsPeerConnection->pSrtpSession, rawPacket, (PINT32) &packetLen));
retStatus = iceAgentSendPacket(pKvsPeerConnection->pIceAgent, rawPacket, packetLen);
} else {
CHK_STATUS(constructRetransmitRtpPacketFromBytes(
rawPacket, packetLen, pSenderTranceiver->sender.rtxSequenceNumber,
pSenderTranceiver->sender.rtxPayloadType, pSenderTranceiver->sender.rtxSsrc, &pRtxRtpPacket));
pSenderTranceiver->sender.rtxSequenceNumber++;
retStatus = writeRtpPacket(pKvsPeerConnection, pRtxRtpPacket);
}
// resendPacket
if (STATUS_SUCCEEDED(retStatus)) {
retransmittedPacketsSent++;
retransmittedBytesSent += pRtpPacketRef->refLength;
DLOGV("Resent packet succeeded");
/* FIXME: The shared buffer RTP packet should be counted into twcc manager. */
// twccManagerOnPacketSent(pKvsPeerConnection, pRtpPacket);
} else {
DLOGV("Resent packet failed 0x%08x", retStatus);
}
// putBackPacketToRollingBuffer
retStatus =
rollingBufferInsertData(pSenderTranceiver->sender.packetBuffer->pRollingBuffer, pRetransmitter->sequenceNumberList[index], item);
CHK(retStatus == STATUS_SUCCESS || retStatus == STATUS_ROLLING_BUFFER_NOT_IN_RANGE, retStatus);
// free the packet if it is not in the valid range any more
if (retStatus == STATUS_ROLLING_BUFFER_NOT_IN_RANGE) {
DLOGS("Retransmit STATUS_ROLLING_BUFFER_NOT_IN_RANGE free %lu by self", pRtpPacket->header.sequenceNumber);
free(pRtpPacketRef);
retStatus = STATUS_SUCCESS;
} else {
DLOGS("Retransmit add back to rolling %lu", pRtpPacket->header.sequenceNumber);
}
freeRtpPacket(&pRtxRtpPacket);
SAFE_MEMFREE(rawPacket);
}
}
CleanUp:
MUTEX_LOCK(pSenderTranceiver->statsLock);
pSenderTranceiver->outboundStats.nackCount += nackCount;
pSenderTranceiver->outboundStats.retransmittedPacketsSent += retransmittedPacketsSent;
pSenderTranceiver->outboundStats.retransmittedBytesSent += retransmittedBytesSent;
MUTEX_UNLOCK(pSenderTranceiver->statsLock);
CHK_LOG_ERR(retStatus);
SAFE_MEMFREE(rawPacket);
LEAVES();
return retStatus;
}