STATUS resendPacketOnNack()

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;
}