Merge pull request #3274 from wangyix/leo_stats

Added domain setting to make AudioMixer print audiostream stats to stdout every second;  Added per-report prints to jittertester
This commit is contained in:
Leonardo Murillo 2014-08-13 10:43:20 -07:00
commit 08382327b4
8 changed files with 207 additions and 20 deletions

View file

@ -71,6 +71,8 @@ bool AudioMixer::_useDynamicJitterBuffers = false;
int AudioMixer::_staticDesiredJitterBufferFrames = 0;
int AudioMixer::_maxFramesOverDesired = 0;
bool AudioMixer::_printStreamStats = false;
AudioMixer::AudioMixer(const QByteArray& packet) :
ThreadedAssignment(packet),
_trailingSleepRatio(1.0f),
@ -448,7 +450,11 @@ void AudioMixer::run() {
}
qDebug() << "Max frames over desired:" << _maxFramesOverDesired;
const QString PRINT_STREAM_STATS_JSON_KEY = "H-print-stream-stats";
_printStreamStats = audioGroupObject[PRINT_STREAM_STATS_JSON_KEY].toBool();
if (_printStreamStats) {
qDebug() << "Stream stats will be printed to stdout";
}
const QString UNATTENUATED_ZONE_KEY = "D-unattenuated-zone";
@ -547,6 +553,7 @@ void AudioMixer::run() {
sendAudioStreamStats = true;
}
bool streamStatsPrinted = false;
foreach (const SharedNodePointer& node, nodeList->getNodeHash()) {
if (node->getLinkedData()) {
AudioMixerClientData* nodeData = (AudioMixerClientData*)node->getLinkedData();
@ -581,12 +588,21 @@ void AudioMixer::run() {
// send an audio stream stats packet if it's time
if (sendAudioStreamStats) {
nodeData->sendAudioStreamStatsPackets(node);
if (_printStreamStats) {
printf("\nStats for agent %s:\n", node->getUUID().toString().toLatin1().data());
nodeData->printUpstreamDownstreamStats();
streamStatsPrinted = true;
}
}
++_sumListeners;
}
}
}
if (streamStatsPrinted) {
printf("\n----------------------------------------------------------------\n");
}
++_numStatFrames;

View file

@ -66,6 +66,8 @@ private:
static int _staticDesiredJitterBufferFrames;
static int _maxFramesOverDesired;
static bool _printStreamStats;
quint64 _lastSendAudioStreamStatsTime;
};

View file

@ -22,7 +22,8 @@
AudioMixerClientData::AudioMixerClientData() :
_audioStreams(),
_outgoingMixedAudioSequenceNumber(0)
_outgoingMixedAudioSequenceNumber(0),
_downstreamAudioStreamStats()
{
}
@ -263,3 +264,45 @@ QString AudioMixerClientData::getAudioStreamStatsString() const {
}
return result;
}
void AudioMixerClientData::printUpstreamDownstreamStats() const {
// print the upstream (mic stream) stats if the mic stream exists
if (_audioStreams.contains(QUuid())) {
printf("Upstream:\n");
printAudioStreamStats(_audioStreams.value(QUuid())->getAudioStreamStats());
}
// print the downstream stats if they contain valid info
if (_downstreamAudioStreamStats._packetStreamStats._received > 0) {
printf("Downstream:\n");
printAudioStreamStats(_downstreamAudioStreamStats);
}
}
void AudioMixerClientData::printAudioStreamStats(const AudioStreamStats& streamStats) const {
printf(" Packet loss | overall: %5.2f%% (%d lost), last_30s: %5.2f%% (%d lost)\n",
streamStats._packetStreamStats.getLostRate() * 100.0f,
streamStats._packetStreamStats._lost,
streamStats._packetStreamWindowStats.getLostRate() * 100.0f,
streamStats._packetStreamWindowStats._lost);
printf(" Ringbuffer frames | desired: %u, avg_available(10s): %u, available: %u\n",
streamStats._desiredJitterBufferFrames,
streamStats._framesAvailableAverage,
streamStats._framesAvailable);
printf(" Ringbuffer stats | starves: %u, prev_starve_lasted: %u, frames_dropped: %u, overflows: %u\n",
streamStats._starveCount,
streamStats._consecutiveNotMixedCount,
streamStats._framesDropped,
streamStats._overflowCount);
printf(" Inter-packet timegaps (overall) | min: %9s, max: %9s, avg: %9s\n",
formatUsecTime(streamStats._timeGapMin).toLatin1().data(),
formatUsecTime(streamStats._timeGapMax).toLatin1().data(),
formatUsecTime(streamStats._timeGapAverage).toLatin1().data());
printf(" Inter-packet timegaps (last 30s) | min: %9s, max: %9s, avg: %9s\n",
formatUsecTime(streamStats._timeGapWindowMin).toLatin1().data(),
formatUsecTime(streamStats._timeGapWindowMax).toLatin1().data(),
formatUsecTime(streamStats._timeGapWindowAverage).toLatin1().data());
}

View file

@ -38,6 +38,11 @@ public:
void incrementOutgoingMixedAudioSequenceNumber() { _outgoingMixedAudioSequenceNumber++; }
quint16 getOutgoingSequenceNumber() const { return _outgoingMixedAudioSequenceNumber; }
void printUpstreamDownstreamStats() const;
private:
void printAudioStreamStats(const AudioStreamStats& streamStats) const;
private:
QHash<QUuid, PositionalAudioStream*> _audioStreams; // mic stream stored under key of null UUID

View file

@ -21,6 +21,12 @@
"placeholder": "10",
"default": "10"
},
"H-print-stream-stats": {
"type": "checkbox",
"label": "Print Stream Stats:",
"help": "If enabled, audio upstream and downstream stats of each agent will be printed each second to stdout",
"default": false
},
"D-unattenuated-zone": {
"label": "Unattenuated Zone",
"help": "Boxes for source and listener (corner x, corner y, corner z, size x, size y, size z, corner x, corner y, corner z, size x, size y, size z)",

View file

@ -253,14 +253,19 @@ PacketStreamStats SequenceNumberStats::getStatsForHistoryWindow() const {
}
// calculate difference between newest stats and oldest stats to get window stats
PacketStreamStats windowStats;
windowStats._received = newestStats->_received - oldestStats->_received;
windowStats._unreasonable = newestStats->_unreasonable - oldestStats->_unreasonable;
windowStats._early = newestStats->_early - oldestStats->_early;
windowStats._late = newestStats->_late - oldestStats->_late;
windowStats._lost = newestStats->_lost - oldestStats->_lost;
windowStats._recovered = newestStats->_recovered - oldestStats->_recovered;
windowStats._expectedReceived = newestStats->_expectedReceived - oldestStats->_expectedReceived;
return windowStats;
return *newestStats - *oldestStats;
}
PacketStreamStats SequenceNumberStats::getStatsForLastHistoryInterval() const {
const PacketStreamStats* newestStats = _statsHistory.getNewestEntry();
const PacketStreamStats* secondNewestStats = _statsHistory.get(1);
// this catches cases where history is length 1 or 0 (both are NULL in case of 0)
if (newestStats == NULL || secondNewestStats == NULL) {
return PacketStreamStats();
}
return *newestStats - *secondNewestStats;
}

View file

@ -31,6 +31,18 @@ public:
_expectedReceived(0)
{}
PacketStreamStats operator-(const PacketStreamStats& rhs) const {
PacketStreamStats diff;
diff._received = _received - rhs._received;
diff._unreasonable = _unreasonable - rhs._unreasonable;
diff._early = _early - rhs._early;
diff._late = _late - rhs._late;
diff._lost = _lost - rhs._lost;
diff._recovered = _recovered - rhs._recovered;
diff._expectedReceived = _expectedReceived - rhs._expectedReceived;
return diff;
}
float getLostRate() const { return (float)_lost / _expectedReceived; }
quint32 _received;
@ -76,6 +88,7 @@ public:
const PacketStreamStats& getStats() const { return _stats; }
PacketStreamStats getStatsForHistoryWindow() const;
PacketStreamStats getStatsForLastHistoryInterval() const;
const QSet<quint16>& getMissingSet() const { return _missingSet; }
private:

View file

@ -16,6 +16,8 @@
#include <stdio.h>
#include <MovingMinMaxAvg.h> // for MovingMinMaxAvg
#include <SequenceNumberStats.h>
#include <StdDev.h>
#include <SharedUtil.h> // for usecTimestampNow
const quint64 MSEC_TO_USEC = 1000;
@ -61,6 +63,8 @@ void runSend(const char* addressOption, int port, int gap, int size, int report)
char* outputBuffer = new char[size];
memset(outputBuffer, 0, size);
quint16 outgoingSequenceNumber = 0;
sockfd=socket(AF_INET,SOCK_DGRAM,0);
@ -74,6 +78,16 @@ void runSend(const char* addressOption, int port, int gap, int size, int report)
std::cout << "SAMPLES_FOR_30_SECONDS:" << SAMPLES_FOR_30_SECONDS << "\n";
MovingMinMaxAvg<int> timeGaps(1, SAMPLES_FOR_30_SECONDS); // stats
const int SAMPLES_PER_REPORT = report * MSEC_TO_USEC / gap;
std::cout << "SAMPLES_PER_REPORT:" << SAMPLES_PER_REPORT << "\n";
MovingMinMaxAvg<int> timeGapsPerReport(1, SAMPLES_PER_REPORT);
StDev stDevReportInterval;
StDev stDev30s;
StDev stDev;
quint64 last = usecTimestampNow();
quint64 lastReport = 0;
@ -85,21 +99,47 @@ void runSend(const char* addressOption, int port, int gap, int size, int report)
if (actualGap >= gap) {
// pack seq num
memcpy(outputBuffer, &outgoingSequenceNumber, sizeof(quint16));
sendto(sockfd, outputBuffer, size, 0, (struct sockaddr *)&servaddr, sizeof(servaddr));
outgoingSequenceNumber++;
int gapDifferece = actualGap - gap;
timeGaps.update(gapDifferece);
timeGapsPerReport.update(gapDifferece);
stDev.addValue(gapDifferece);
stDev30s.addValue(gapDifferece);
stDevReportInterval.addValue(gapDifferece);
last = now;
if (now - lastReport >= (report * MSEC_TO_USEC)) {
std::cout << "SEND gap Difference From Expected "
std::cout << "\n"
<< "SEND gap Difference From Expected\n"
<< "Overall:\n"
<< "min: " << timeGaps.getMin() << " usecs, "
<< "max: " << timeGaps.getMax() << " usecs, "
<< "avg: " << timeGaps.getAverage() << " usecs, "
<< "min last 30: " << timeGaps.getWindowMin() << " usecs, "
<< "max last 30: " << timeGaps.getWindowMax() << " usecs, "
<< "avg last 30: " << timeGaps.getWindowAverage() << " usecs "
<< "stdev: " << stDev.getStDev() << " usecs\n"
<< "Last 30s:\n"
<< "min: " << timeGaps.getWindowMin() << " usecs, "
<< "max: " << timeGaps.getWindowMax() << " usecs, "
<< "avg: " << timeGaps.getWindowAverage() << " usecs, "
<< "stdev: " << stDev30s.getStDev() << " usecs\n"
<< "Last report interval:\n"
<< "min: " << timeGapsPerReport.getWindowMin() << " usecs, "
<< "max: " << timeGapsPerReport.getWindowMax() << " usecs, "
<< "avg: " << timeGapsPerReport.getWindowAverage() << " usecs, "
<< "stdev: " << stDevReportInterval.getStDev() << " usecs\n"
<< "\n";
stDevReportInterval.reset();
if (stDev30s.getSamples() > SAMPLES_FOR_30_SECONDS) {
stDev30s.reset();
}
lastReport = now;
}
}
@ -129,6 +169,22 @@ void runReceive(const char* addressOption, int port, int gap, int size, int repo
MovingMinMaxAvg<int> timeGaps(1, SAMPLES_FOR_30_SECONDS); // stats
const int SAMPLES_PER_REPORT = report * MSEC_TO_USEC / gap;
std::cout << "SAMPLES_PER_REPORT:" << SAMPLES_PER_REPORT << "\n";
MovingMinMaxAvg<int> timeGapsPerReport(1, SAMPLES_PER_REPORT);
const int REPORTS_FOR_30_SECONDS = 30 * MSECS_PER_SECOND / report;
std::cout << "REPORTS_FOR_30_SECONDS:" << REPORTS_FOR_30_SECONDS << "\n";
SequenceNumberStats seqStats(REPORTS_FOR_30_SECONDS);
StDev stDevReportInterval;
StDev stDev30s;
StDev stDev;
if (bind(sockfd, (struct sockaddr *)&myaddr, sizeof(myaddr)) < 0) {
std::cout << "bind failed\n";
return;
@ -139,6 +195,10 @@ void runReceive(const char* addressOption, int port, int gap, int size, int repo
while (true) {
n = recvfrom(sockfd, inputBuffer, size, 0, NULL, NULL); // we don't care about where it came from
// parse seq num
quint16 incomingSequenceNumber = *(reinterpret_cast<quint16*>(inputBuffer));
seqStats.sequenceNumberReceived(incomingSequenceNumber);
if (last == 0) {
last = usecTimestampNow();
@ -148,17 +208,54 @@ void runReceive(const char* addressOption, int port, int gap, int size, int repo
int actualGap = now - last;
int gapDifferece = actualGap - gap;
timeGaps.update(gapDifferece);
timeGapsPerReport.update(gapDifferece);
stDev.addValue(gapDifferece);
stDev30s.addValue(gapDifferece);
stDevReportInterval.addValue(gapDifferece);
last = now;
if (now - lastReport >= (report * MSEC_TO_USEC)) {
std::cout << "RECEIVE gap Difference From Expected "
seqStats.pushStatsToHistory();
std::cout << "RECEIVE gap Difference From Expected\n"
<< "Overall:\n"
<< "min: " << timeGaps.getMin() << " usecs, "
<< "max: " << timeGaps.getMax() << " usecs, "
<< "avg: " << timeGaps.getAverage() << " usecs, "
<< "min last 30: " << timeGaps.getWindowMin() << " usecs, "
<< "max last 30: " << timeGaps.getWindowMax() << " usecs, "
<< "avg last 30: " << timeGaps.getWindowAverage() << " usecs "
<< "stdev: " << stDev.getStDev() << " usecs\n"
<< "Last 30s:\n"
<< "min: " << timeGaps.getWindowMin() << " usecs, "
<< "max: " << timeGaps.getWindowMax() << " usecs, "
<< "avg: " << timeGaps.getWindowAverage() << " usecs, "
<< "stdev: " << stDev30s.getStDev() << " usecs\n"
<< "Last report interval:\n"
<< "min: " << timeGapsPerReport.getWindowMin() << " usecs, "
<< "max: " << timeGapsPerReport.getWindowMax() << " usecs, "
<< "avg: " << timeGapsPerReport.getWindowAverage() << " usecs, "
<< "stdev: " << stDevReportInterval.getStDev() << " usecs\n"
<< "\n";
stDevReportInterval.reset();
if (stDev30s.getSamples() > SAMPLES_FOR_30_SECONDS) {
stDev30s.reset();
}
PacketStreamStats packetStatsLast30s = seqStats.getStatsForHistoryWindow();
PacketStreamStats packetStatsLastReportInterval = seqStats.getStatsForLastHistoryInterval();
std::cout << "RECEIVE Packet Stats\n"
<< "Overall:\n"
<< "lost: " << seqStats.getLost() << ", "
<< "lost %: " << seqStats.getStats().getLostRate() * 100.0f << "%\n"
<< "Last 30s:\n"
<< "lost: " << packetStatsLast30s._lost << ", "
<< "lost %: " << packetStatsLast30s.getLostRate() * 100.0f << "%\n"
<< "Last report interval:\n"
<< "lost: " << packetStatsLastReportInterval._lost << ", "
<< "lost %: " << packetStatsLastReportInterval.getLostRate() * 100.0f << "%\n"
<< "\n\n";
lastReport = now;
}
}