void RTPReceptionStatsDB ::noteIncomingPacket(u_int32_t SSRC, u_int16_t seqNum, u_int32_t rtpTimestamp, unsigned timestampFrequency, Boolean useForJitterCalculation, struct timeval& resultPresentationTime, Boolean& resultHasBeenSyncedUsingRTCP, unsigned packetSize) { ++fTotNumPacketsReceived; RTPReceptionStats* stats = lookup(SSRC); if (stats == NULL) { // This is the first time we've heard from this SSRC. // Create a new record for it: stats = new RTPReceptionStats(SSRC, seqNum); if (stats == NULL) return; add(SSRC, stats); } if (stats->numPacketsReceivedSinceLastReset() == 0) { ++fNumActiveSourcesSinceLastReset; } stats->noteIncomingPacket(seqNum, rtpTimestamp, timestampFrequency, useForJitterCalculation, resultPresentationTime, resultHasBeenSyncedUsingRTCP, packetSize); }
qosMeasurementRecord(struct timeval const& startTime, RTPSource* src) : fSource(src), fNext(NULL), kbits_per_second_min(1e20), kbits_per_second_max(0), kBytesTotal(0.0), packet_loss_fraction_min(1.0), packet_loss_fraction_max(0.0), totNumPacketsReceived(0), totNumPacketsExpected(0) { measurementEndTime = measurementStartTime = startTime; #ifdef SUPPORT_REAL_RTSP if (session->isRealNetworksRDT) { // hack for RealMedia sessions (RDT, not RTP) RealRDTSource* rdt = (RealRDTSource*)src; kBytesTotal = rdt->totNumKBytesReceived(); totNumPacketsReceived = rdt->totNumPacketsReceived(); totNumPacketsExpected = totNumPacketsReceived; // because we use TCP return; } #endif RTPReceptionStatsDB::Iterator statsIter(src->receptionStatsDB()); // Assume that there's only one SSRC source (usually the case): RTPReceptionStats* stats = statsIter.next(True); if (stats != NULL) { kBytesTotal = stats->totNumKBytesReceived(); totNumPacketsReceived = stats->totNumPacketsReceived(); totNumPacketsExpected = stats->totNumPacketsExpected(); } }
void qosMeasurementRecord ::periodicQOSMeasurement(struct timeval const& timeNow) { unsigned secsDiff = timeNow.tv_sec - measurementEndTime.tv_sec; int usecsDiff = timeNow.tv_usec - measurementEndTime.tv_usec; double timeDiff = secsDiff + usecsDiff/1000000.0; measurementEndTime = timeNow; #ifdef SUPPORT_REAL_RTSP if (session->isRealNetworksRDT) { // hack for RealMedia sessions (RDT, not RTP) RealRDTSource* rdt = (RealRDTSource*)fSource; double kBytesTotalNow = rdt->totNumKBytesReceived(); double kBytesDeltaNow = kBytesTotalNow - kBytesTotal; kBytesTotal = kBytesTotalNow; double kbpsNow = timeDiff == 0.0 ? 0.0 : 8*kBytesDeltaNow/timeDiff; if (kbpsNow < 0.0) kbpsNow = 0.0; // in case of roundoff error if (kbpsNow < kbits_per_second_min) kbits_per_second_min = kbpsNow; if (kbpsNow > kbits_per_second_max) kbits_per_second_max = kbpsNow; totNumPacketsReceived = rdt->totNumPacketsReceived(); totNumPacketsExpected = totNumPacketsReceived; // because we use TCP packet_loss_fraction_min = packet_loss_fraction_max = 0.0; // ditto return; } #endif RTPReceptionStatsDB::Iterator statsIter(fSource->receptionStatsDB()); // Assume that there's only one SSRC source (usually the case): RTPReceptionStats* stats = statsIter.next(True); if (stats != NULL) { double kBytesTotalNow = stats->totNumKBytesReceived(); double kBytesDeltaNow = kBytesTotalNow - kBytesTotal; kBytesTotal = kBytesTotalNow; double kbpsNow = timeDiff == 0.0 ? 0.0 : 8*kBytesDeltaNow/timeDiff; if (kbpsNow < 0.0) kbpsNow = 0.0; // in case of roundoff error if (kbpsNow < kbits_per_second_min) kbits_per_second_min = kbpsNow; if (kbpsNow > kbits_per_second_max) kbits_per_second_max = kbpsNow; unsigned totReceivedNow = stats->totNumPacketsReceived(); unsigned totExpectedNow = stats->totNumPacketsExpected(); unsigned deltaReceivedNow = totReceivedNow - totNumPacketsReceived; unsigned deltaExpectedNow = totExpectedNow - totNumPacketsExpected; totNumPacketsReceived = totReceivedNow; totNumPacketsExpected = totExpectedNow; double lossFractionNow = deltaExpectedNow == 0 ? 0.0 : 1.0 - deltaReceivedNow/(double)deltaExpectedNow; //if (lossFractionNow < 0.0) lossFractionNow = 0.0; //reordering can cause if (lossFractionNow < packet_loss_fraction_min) { packet_loss_fraction_min = lossFractionNow; } if (lossFractionNow > packet_loss_fraction_max) { packet_loss_fraction_max = lossFractionNow; } } }
void RTPReceptionStatsDB::reset() { fNumActiveSourcesSinceLastReset = 0; Iterator iter(*this); RTPReceptionStats* stats; while ((stats = iter.next()) != NULL) { stats->reset(); } }
RTPReceptionStats* RTPReceptionStatsDB::Iterator::next(Boolean includeInactiveSources) { char const* key; // dummy // If asked, skip over any sources that haven't been active // since the last reset: RTPReceptionStats* stats; do { stats = (RTPReceptionStats*)(fIter->next(key)); } while (stats != NULL && !includeInactiveSources && stats->numPacketsReceivedSinceLastReset() == 0); return stats; }
void RTPReceptionStatsDB ::noteIncomingSR(u_int32_t SSRC, u_int32_t ntpTimestampMSW, u_int32_t ntpTimestampLSW, u_int32_t rtpTimestamp) { RTPReceptionStats* stats = lookup(SSRC); if (stats == NULL) { // This is the first time we've heard of this SSRC. // Create a new record for it: stats = new RTPReceptionStats(SSRC); if (stats == NULL) return; add(SSRC, stats); } stats->noteIncomingSR(ntpTimestampMSW, ntpTimestampLSW, rtpTimestamp); }
qosMeasurementRecord(struct timeval const& startTime, RTPSource* src) : fSource(src), fNext(NULL), kbits_per_second_min(1e20), kbits_per_second_max(0), kBytesTotal(0.0), packet_loss_fraction_min(1.0), packet_loss_fraction_max(0.0), totNumPacketsReceived(0), totNumPacketsExpected(0) { measurementEndTime = measurementStartTime = startTime; RTPReceptionStatsDB::Iterator statsIter(src->receptionStatsDB()); // Assume that there's only one SSRC source (usually the case): RTPReceptionStats* stats = statsIter.next(True); if (stats != NULL) { kBytesTotal = stats->totNumKBytesReceived(); totNumPacketsReceived = stats->totNumPacketsReceived(); totNumPacketsExpected = stats->totNumPacketsExpected(); } }
static void qos_report(void *clientData) { int i; struct timeval now; long long elapsed; // gettimeofday(&now, NULL); elapsed = tvdiff_us(&now, &qos_tv); for(i = 0; i < n_qrec; i++) { RTPReceptionStatsDB::Iterator statsIter(qrec[i].rtpsrc->receptionStatsDB()); // Assume that there's only one SSRC source (usually the case): RTPReceptionStats* stats = statsIter.next(True); unsigned pkts_expected, dExp; unsigned pkts_received, dRcvd; double KB_received, dKB; // if(stats == NULL) continue; pkts_expected = stats->totNumPacketsExpected(); pkts_received = stats->totNumPacketsReceived(); KB_received = stats->totNumKBytesReceived(); // delta ... dExp = pkts_expected - qrec[i].pkts_expected; dRcvd = pkts_received - qrec[i].pkts_received; dKB = KB_received - qrec[i].KB_received; // show info ga_error("%s-report: %.0fKB rcvd; pkt-loss=%d/%d,%.2f%%; bitrate=%.0fKbps; jitter=%u (freq=%uHz)\n", //now.tv_sec, now.tv_usec, qrec[i].prefix, dKB, dExp-dRcvd, dExp, 100.0*(dExp-dRcvd)/dExp, 8000000.0*dKB/elapsed, stats->jitter(), qrec[i].rtpsrc->timestampFrequency()); // qrec[i].pkts_expected = pkts_expected; qrec[i].pkts_received = pkts_received; qrec[i].KB_received = KB_received; } // schedule next qos qos_tv = now; qos_schedule(); return; }
void qosMeasurementRecord ::periodicQOSMeasurement(struct timeval const& timeNow) { unsigned secsDiff = timeNow.tv_sec - measurementEndTime.tv_sec; int usecsDiff = timeNow.tv_usec - measurementEndTime.tv_usec; double timeDiff = secsDiff + usecsDiff/1000000.0; measurementEndTime = timeNow; RTPReceptionStatsDB::Iterator statsIter(fSource->receptionStatsDB()); // Assume that there's only one SSRC source (usually the case): RTPReceptionStats* stats = statsIter.next(True); if (stats != NULL) { double kBytesTotalNow = stats->totNumKBytesReceived(); double kBytesDeltaNow = kBytesTotalNow - kBytesTotal; kBytesTotal = kBytesTotalNow; double kbpsNow = timeDiff == 0.0 ? 0.0 : 8*kBytesDeltaNow/timeDiff; if (kbpsNow < 0.0) kbpsNow = 0.0; // in case of roundoff error if (kbpsNow < kbits_per_second_min) kbits_per_second_min = kbpsNow; if (kbpsNow > kbits_per_second_max) kbits_per_second_max = kbpsNow; unsigned totReceivedNow = stats->totNumPacketsReceived(); unsigned totExpectedNow = stats->totNumPacketsExpected(); unsigned deltaReceivedNow = totReceivedNow - totNumPacketsReceived; unsigned deltaExpectedNow = totExpectedNow - totNumPacketsExpected; totNumPacketsReceived = totReceivedNow; totNumPacketsExpected = totExpectedNow; double lossFractionNow = deltaExpectedNow == 0 ? 0.0 : 1.0 - deltaReceivedNow/(double)deltaExpectedNow; //if (lossFractionNow < 0.0) lossFractionNow = 0.0; //reordering can cause if (lossFractionNow < packet_loss_fraction_min) { packet_loss_fraction_min = lossFractionNow; } if (lossFractionNow > packet_loss_fraction_max) { packet_loss_fraction_max = lossFractionNow; } } }
void printQOSData(int exitCode) { *env << "begin_QOS_statistics\n"; // Print out stats for each active subsession: qosMeasurementRecord* curQOSRecord = qosRecordHead; if (session != NULL) { MediaSubsessionIterator iter(*session); MediaSubsession* subsession; while ((subsession = iter.next()) != NULL) { RTPSource* src = subsession->rtpSource(); if (src == NULL) continue; *env << "subsession\t" << subsession->mediumName() << "/" << subsession->codecName() << "\n"; unsigned numPacketsReceived = 0, numPacketsExpected = 0; if (curQOSRecord != NULL) { numPacketsReceived = curQOSRecord->totNumPacketsReceived; numPacketsExpected = curQOSRecord->totNumPacketsExpected; } *env << "num_packets_received\t" << numPacketsReceived << "\n"; *env << "num_packets_lost\t" << int(numPacketsExpected - numPacketsReceived) << "\n"; if (curQOSRecord != NULL) { unsigned secsDiff = curQOSRecord->measurementEndTime.tv_sec - curQOSRecord->measurementStartTime.tv_sec; int usecsDiff = curQOSRecord->measurementEndTime.tv_usec - curQOSRecord->measurementStartTime.tv_usec; double measurementTime = secsDiff + usecsDiff/1000000.0; *env << "elapsed_measurement_time\t" << measurementTime << "\n"; *env << "kBytes_received_total\t" << curQOSRecord->kBytesTotal << "\n"; *env << "measurement_sampling_interval_ms\t" << qosMeasurementIntervalMS << "\n"; if (curQOSRecord->kbits_per_second_max == 0) { // special case: we didn't receive any data: *env << "kbits_per_second_min\tunavailable\n" "kbits_per_second_ave\tunavailable\n" "kbits_per_second_max\tunavailable\n"; } else { *env << "kbits_per_second_min\t" << curQOSRecord->kbits_per_second_min << "\n"; *env << "kbits_per_second_ave\t" << (measurementTime == 0.0 ? 0.0 : 8*curQOSRecord->kBytesTotal/measurementTime) << "\n"; *env << "kbits_per_second_max\t" << curQOSRecord->kbits_per_second_max << "\n"; } *env << "packet_loss_percentage_min\t" << 100*curQOSRecord->packet_loss_fraction_min << "\n"; double packetLossFraction = numPacketsExpected == 0 ? 1.0 : 1.0 - numPacketsReceived/(double)numPacketsExpected; if (packetLossFraction < 0.0) packetLossFraction = 0.0; *env << "packet_loss_percentage_ave\t" << 100*packetLossFraction << "\n"; *env << "packet_loss_percentage_max\t" << (packetLossFraction == 1.0 ? 100.0 : 100*curQOSRecord->packet_loss_fraction_max) << "\n"; RTPReceptionStatsDB::Iterator statsIter(src->receptionStatsDB()); // Assume that there's only one SSRC source (usually the case): RTPReceptionStats* stats = statsIter.next(True); if (stats != NULL) { *env << "inter_packet_gap_ms_min\t" << stats->minInterPacketGapUS()/1000.0 << "\n"; struct timeval totalGaps = stats->totalInterPacketGaps(); double totalGapsMS = totalGaps.tv_sec*1000.0 + totalGaps.tv_usec/1000.0; unsigned totNumPacketsReceived = stats->totNumPacketsReceived(); *env << "inter_packet_gap_ms_ave\t" << (totNumPacketsReceived == 0 ? 0.0 : totalGapsMS/totNumPacketsReceived) << "\n"; *env << "inter_packet_gap_ms_max\t" << stats->maxInterPacketGapUS()/1000.0 << "\n"; } curQOSRecord = curQOSRecord->fNext; } } } *env << "end_QOS_statistics\n"; delete qosRecordHead; }