static int streamxmit_retransmitRtp(STREAM_RTP_DEST_T *pDest) { STREAMXMIT_PKT_HDR_T *pktHdr; unsigned int idxRd; unsigned int count = 0; int lastWasExpired = 0; int rc; int haveRequestedRetransmission = 0; const PKTQUEUE_PKT_T *pQPkt = NULL; STREAM_XMIT_QUEUE_T *pAsyncQ = &pDest->asyncQ; TIME_VAL tvNow; struct timeval tv; float kbps; char tmp[128]; tvNow = timer_GetTime(); TV_FROM_TIMEVAL(tv, tvNow); pthread_mutex_lock(&pAsyncQ->mtx); idxRd = pAsyncQ->pQ->idxRd; //LOG(X_DEBUG("NACK streamxmit_iterate ... idxRd:%d, idxWr:%d / %d"), pAsyncQ->pQ->idxRd, pAsyncQ->pQ->idxWr, pAsyncQ->pQ->cfg.maxPkts); while(count++ < pAsyncQ->pQ->cfg.maxPkts) { pQPkt = &pAsyncQ->pQ->pkts[idxRd]; if(!(pQPkt->flags & PKTQUEUE_FLAG_HAVEPKTDATA)) { //LOG(X_DEBUG("NACK streamxmit_iterate break at qid[%d]"), idxRd); break; } //LOG(X_DEBUG("NACK streamxmit_iterate check qid[%d] seqno:%d, %lld ms ago"), idxRd, ((STREAMXMIT_PKT_HDR_T *) pQPkt->xtra.pQUserData)->seqNum, (tvNow - ((STREAMXMIT_PKT_HDR_T *) pQPkt->xtra.pQUserData)->tvxmit)/1000); lastWasExpired = 0; if(!(pktHdr = (STREAMXMIT_PKT_HDR_T *) pQPkt->xtra.pQUserData)) { pAsyncQ->pQ->idxRd = idxRd; fprintf(stderr, "streamxmit_itertate should never get here... idxRd:%d\n", idxRd); } else if(pktHdr->tvXmit + (pAsyncQ->nackHistoryMs * TIME_VAL_MS) < tvNow) { // // The queue slot RTP sequence number came before the NACK starting sequence number // so the current queue content is before the scope of the NACK // if(pktHdr->doRetransmit > 0) { pktHdr->doRetransmit = -1; if(pDest->pstreamStats) { stream_abr_notifyBitrate(pDest->pstreamStats, &pDest->streamStatsMtx, STREAM_ABR_UPDATE_REASON_NACK_AGED, .5f); } } pAsyncQ->pQ->idxRd = idxRd; pAsyncQ->pQ->pkts[idxRd].flags = 0; lastWasExpired = 1; //LOG(X_DEBUG("NACK streamxmit_iterate old here marked to -1 ... idxRd:%d, seqNum:%d"), idxRd, pktHdr->seqNum); } else if(pktHdr->doRetransmit > 0 && !pktHdr->rtcp) { if(pktHdr->tvLastRetransmit == 0 || pktHdr->tvLastRetransmit + (RTP_RETRANSMIT_INTERVAL_MS * TIME_VAL_MS) < tvNow) { // // Ensure that the retransmission will not exceed our retransmission bitrate limit // if(pAsyncQ->retransmissionKbpsMax > 0 && burstmeter_updateCounters(&pAsyncQ->retransmissionMeter, &tv) == 0 && (kbps = (burstmeter_getBitrateBps(&pAsyncQ->retransmissionMeter)/THROUGHPUT_BYTES_IN_KILO_F)) >= pAsyncQ->retransmissionKbpsMax) { LOG(X_WARNING("RTP NACK retransmission bitrate %.3f >= %.3f throttled pt:%d sequence:%d to %s:%d, for original %d ms ago."), kbps, pAsyncQ->retransmissionKbpsMax, pDest->pRtpMulti->init.pt, pktHdr->seqNum, FORMAT_NETADDR(pDest->saDstsRtcp, tmp, sizeof(tmp)), ntohs(INET_PORT(pDest->saDstsRtcp)), (tvNow - pktHdr->tvXmit) / TIME_VAL_MS); if(pDest->pstreamStats) { stream_abr_notifyBitrate(pDest->pstreamStats, &pDest->streamStatsMtx, STREAM_ABR_UPDATE_REASON_NACK_THROTTLED, .5f); } pktHdr->doRetransmit = 0; pktHdr->tvLastRetransmit = tvNow; } else { burstmeter_AddSample(&pAsyncQ->retransmissionMeter, pQPkt->len, &tv); //LOG(X_DEBUG("RTP NACK Retransmission bitrate: %.3f %s (%.3f bps)"), (float) pAsyncQ->retransmissionMeter.meter.rangeMs/1000, burstmeter_printThroughputStr(buf, sizeof(buf), &pAsyncQ->retransmissionMeter), (float) burstmeter_getBitrateBps(&pAsyncQ->retransmissionMeter)); // // Retransmit the RTP packet // LOG(X_DEBUG("RTP NACK retransmitting pt:%d sequence:%d, len:%d to %s:%d, original sent %d ms ago. " "Rate: %.3f pkts/s, %.3f b/s"), pDest->pRtpMulti->init.pt, pktHdr->seqNum, pQPkt->len, FORMAT_NETADDR(pDest->saDstsRtcp, tmp, sizeof(tmp)), ntohs(INET_PORT(pDest->saDstsRtcp)), (tvNow - pktHdr->tvXmit) / TIME_VAL_MS, (float) burstmeter_getPacketratePs(&pAsyncQ->retransmissionMeter), (float) burstmeter_getBitrateBps(&pAsyncQ->retransmissionMeter)); if((rc = srtp_sendto(STREAM_RTP_PNETIOSOCK(*pDest), (void *) pQPkt->pData, pQPkt->len, 0, (const struct sockaddr *) &pDest->saDsts, NULL, SENDTO_PKT_TYPE_RTP, 1)) < 0) { pktHdr->doRetransmit = -1; } else { pktHdr->doRetransmit = 0; } pktHdr->tvLastRetransmit = tvNow; if(pDest->pstreamStats) { stream_abr_notifyBitrate(pDest->pstreamStats, &pDest->streamStatsMtx, STREAM_ABR_UPDATE_REASON_NACK_RETRANSMITTED, .5f); } } } else { haveRequestedRetransmission = 1; } } if(++idxRd >= pAsyncQ->pQ->cfg.maxPkts) { idxRd = 0; } if(lastWasExpired) { pAsyncQ->pQ->idxRd = idxRd; } } // end of while... pAsyncQ->haveRequestedRetransmission = haveRequestedRetransmission; pthread_mutex_unlock(&pAsyncQ->mtx); return haveRequestedRetransmission; }
static char *dump_throughput(char *buf, unsigned int szbuf, const char *prfx, THROUGHPUT_STATS_T *pS, int urlidx) { int rc; unsigned int idx; unsigned int idxbuf = 0; char buftmp[256]; if(szbuf > 0) { buf[0] = '\0'; } if(!pS) { return buf; } if(pS->written.bytes > 0) { burstmeter_printBytes(buftmp, sizeof(buftmp), pS->written.bytes); if((urlidx && (rc = snprintf(&buf[idxbuf], szbuf - idxbuf, "&out%d=%s", urlidx, buftmp)) > 0) || (!urlidx && (rc = snprintf(&buf[idxbuf], szbuf - idxbuf, ", %swrote: %s", prfx, buftmp)) > 0)) { idxbuf += rc; } for(idx = 0; idx < sizeof(pS->bitratesWr) / sizeof(pS->bitratesWr[0]); idx++) { if(pS->bitratesWr[idx].meter.rangeMs > 0) { // // Roll up any real-time rate based counters // burstmeter_updateCounters(&pS->bitratesWr[idx], NULL); burstmeter_printThroughput(buftmp, sizeof(buftmp), &pS->bitratesWr[idx]); rc = snprintf(&buf[idxbuf], szbuf - idxbuf, ", %.1f pkts/s", burstmeter_getPacketratePs(&pS->bitratesWr[idx])); idxbuf += rc; if((urlidx && (rc = snprintf(&buf[idxbuf], szbuf - idxbuf, "&out%.0fs%d=%s", (float) pS->bitratesWr[idx].meter.rangeMs/1000.0f, urlidx, buftmp)) > 0) || (!urlidx && (rc = snprintf(&buf[idxbuf], szbuf - idxbuf, ", %.0fs: %s", (float) pS->bitratesWr[idx].meter.rangeMs/1000.0f, buftmp)) > 0)) { idxbuf += rc; } } } } if(pS->read.bytes > 0) { burstmeter_printBytes(buftmp, sizeof(buftmp), pS->read.bytes); if((urlidx && (rc = snprintf(&buf[idxbuf], szbuf - idxbuf, "&in%d=%s", urlidx, buftmp)) > 0) || (!urlidx && (rc = snprintf(&buf[idxbuf], szbuf - idxbuf, ", read: %s", buftmp)) > 0)) { idxbuf += rc; } for(idx = 0; idx < sizeof(pS->bitratesRd) / sizeof(pS->bitratesRd[0]); idx++) { if(pS->bitratesRd[idx].meter.rangeMs > 0) { burstmeter_printThroughput(buftmp, sizeof(buftmp), &pS->bitratesRd[idx]); if((urlidx && (rc = snprintf(&buf[idxbuf], szbuf - idxbuf, "&in%.0fs%d=%s", (float) pS->bitratesRd[idx].meter.rangeMs/1000.0f, urlidx, buftmp)) > 0) || (!urlidx && (rc = snprintf(&buf[idxbuf], szbuf - idxbuf, ", %.0fs: %s", (float) pS->bitratesRd[idx].meter.rangeMs/1000.0f, buftmp)) > 0)) { idxbuf += rc; } } } } if(pS->skipped.bytes > 0) { burstmeter_printBytes(buftmp, sizeof(buftmp), pS->skipped.bytes); if((urlidx && (rc = snprintf(&buf[idxbuf], szbuf - idxbuf, "&skip%d=%s", urlidx, buftmp)) > 0) || (!urlidx && (rc = snprintf(&buf[idxbuf], szbuf - idxbuf, ", skipped: %s", buftmp)) > 0)) { idxbuf += rc; } } if(pS->read.bytes > 0) { burstmeter_printBytes(buftmp, sizeof(buftmp), pS->written.bytes - pS->read.bytes - pS->skipped.bytes); if((urlidx && (rc = snprintf(&buf[idxbuf], szbuf - idxbuf, "&queue%d=%s", urlidx, buftmp)) > 0) || (!urlidx && (rc = snprintf(&buf[idxbuf], szbuf - idxbuf, ", queued: %s", buftmp)) > 0)) { idxbuf += rc; } //fprintf(fp, " %s", printDuration(buftmp, sizeof(buftmp), PTSF_MS(pS->tmLastWr.tm - pS->tmLastRd.tm))); } /* fprintf(fp, "\nwritten:%lld,%lld, read:%lld,%lld, skipped:%lld,%lld { delta:%lld,%lld %.3fms, tmLastWr:%.3f, tmLastRd:%.3f\n", pS->written.bytes, pS->written.slots, pS->read.bytes, pS->read.slots, pS->skipped.bytes, pS->skipped.slots, (pS->written.bytes - pS->read.bytes - pS->skipped.bytes), (pS->written.slots - pS->read.slots - pS->skipped.slots),PTSF_MS(pS->tmLastWr.tm- pS->tmLastRd.tm), PTSF(pS->tmLastWr.tm), PTSF(pS->tmLastRd.tm)); for(idx = 0; idx < sizeof(pS->bitratesWr) / sizeof(pS->bitratesWr[0]); idx++) { if(pS->bitratesWr[idx].meter.rangeMs > 0) { fprintf(fp, "writer - [%d] %dms cur: %.2fKb/s max: %.2fKb/s ", idx, pS->bitratesWr[idx].meter.rangeMs, pS->bitratesWr[idx].meter.cur.bytes * (1000.0f / pS->bitratesWr[idx].meter.rangeMs) / 125.0f, pS->bitratesWr[idx].meter.max.bytes * (1000.0f / pS->bitratesWr[idx].meter.rangeMs) / 125.0f); } } fprintf(fp, "\n"); for(idx = 0; idx < sizeof(pS->bitratesWr) / sizeof(pS->bitratesWr[0]); idx++) { if(pS->bitratesRd[idx].meter.rangeMs > 0) { fprintf(fp, "reader - [%d] %dms cur: %.2fKb/s max: %.2fKb/s ", idx, pS->bitratesRd[idx].meter.rangeMs, pS->bitratesRd[idx].meter.cur.bytes * (1000.0f / pS->bitratesRd[idx].meter.rangeMs) / 125.0f, pS->bitratesRd[idx].meter.max.bytes * (1000.0f / pS->bitratesRd[idx].meter.rangeMs) / 125.0f); } } fprintf(fp, "\n"); */ return buf; }