void stream_stats_addPktSample(STREAM_STATS_T *pStats, pthread_mutex_t *pmtx, unsigned int len, int rtp) { unsigned int idx; struct timeval tv; THROUGHPUT_STATS_T *pThroughput = NULL; BURSTMETER_SAMPLE_SET_T *pbitrates; if(pmtx) { pthread_mutex_lock(pmtx); } if(!pStats || !pStats->active) { if(pmtx) { pthread_mutex_unlock(pmtx); } return; } //LOG(X_DEBUG("stream_stats_addPktSample len:%d, rtp:%d"), len, rtp); if(pStats->numWr > 1 && !rtp) { // This is for RTCP packet accounting pThroughput = &pStats->throughput_rt[1]; } else { // This is for RTP packet accounting or general TCP based flow pThroughput = &pStats->throughput_rt[0]; } pbitrates = pThroughput->bitratesWr; gettimeofday(&tv, NULL); pthread_mutex_lock(&pStats->mtx); if(pStats->active) { if(pThroughput->written.slots == 0) { TIME_TV_SET(pStats->tvstart, tv); } pThroughput->written.bytes += len; pThroughput->written.slots++; for(idx = 0; idx < THROUGHPUT_STATS_BURSTRATES_MAX; idx++) { if(pbitrates[idx].meter.rangeMs > 0) { burstmeter_AddSample(&pbitrates[idx], len, &tv); } } } pthread_mutex_unlock(&pStats->mtx); if(pmtx) { pthread_mutex_unlock(pmtx); } }
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; }