added window PacketStreamStats to AudioStreamStats

This commit is contained in:
wangyix 2014-07-10 16:42:23 -07:00
parent b4c9e51011
commit 25f4f63a1e
8 changed files with 97 additions and 21 deletions

View file

@ -641,9 +641,6 @@ void AudioMixer::run() {
++framesSinceCutoffEvent;
}
const quint64 TOO_LONG_SINCE_LAST_SEND_AUDIO_STREAM_STATS = 1 * USECS_PER_SECOND;
bool sendAudioStreamStats = false;
quint64 now = usecTimestampNow();
if (now - _lastSendAudioStreamStatsTime > TOO_LONG_SINCE_LAST_SEND_AUDIO_STREAM_STATS) {

View file

@ -21,6 +21,8 @@ class AvatarAudioRingBuffer;
const int SAMPLE_PHASE_DELAY_AT_90 = 20;
const quint64 TOO_LONG_SINCE_LAST_SEND_AUDIO_STREAM_STATS = 1 * USECS_PER_SECOND;
/// Handles assignments of type AudioMixer - mixing streams of audio and re-distributing to various clients.
class AudioMixer : public ThreadedAssignment {
Q_OBJECT

View file

@ -20,10 +20,13 @@
#include "AudioMixerClientData.h"
#include "MovingMinMaxAvg.h"
const int INCOMING_SEQ_STATS_HISTORY_LENGTH = INCOMING_SEQ_STATS_HISTORY_LENGTH_SECONDS /
(TOO_LONG_SINCE_LAST_SEND_AUDIO_STREAM_STATS / USECS_PER_SECOND);
AudioMixerClientData::AudioMixerClientData() :
_ringBuffers(),
_outgoingMixedAudioSequenceNumber(0),
_incomingAvatarAudioSequenceNumberStats()
_incomingAvatarAudioSequenceNumberStats(INCOMING_SEQ_STATS_HISTORY_LENGTH)
{
}
@ -89,6 +92,9 @@ int AudioMixerClientData::parseData(const QByteArray& packet) {
// grab the stream identifier for this injected audio
QUuid streamIdentifier = QUuid::fromRfc4122(packet.mid(numBytesForPacketHeader(packet) + sizeof(quint16), NUM_BYTES_RFC4122_UUID));
if (!_incomingInjectedAudioSequenceNumberStatsMap.contains(streamIdentifier)) {
_incomingInjectedAudioSequenceNumberStatsMap.insert(streamIdentifier, SequenceNumberStats(INCOMING_SEQ_STATS_HISTORY_LENGTH));
}
_incomingInjectedAudioSequenceNumberStatsMap[streamIdentifier].sequenceNumberReceived(sequence);
InjectedAudioRingBuffer* matchingInjectedRingBuffer = NULL;
@ -175,11 +181,14 @@ AudioStreamStats AudioMixerClientData::getAudioStreamStatsOfStream(const Positio
streamStats._streamType = ringBuffer->getType();
if (streamStats._streamType == PositionalAudioRingBuffer::Injector) {
streamStats._streamIdentifier = ((InjectedAudioRingBuffer*)ringBuffer)->getStreamIdentifier();
streamStats._packetStreamStats = _incomingInjectedAudioSequenceNumberStatsMap[streamStats._streamIdentifier].getStats();
const SequenceNumberStats& sequenceNumberStats = _incomingInjectedAudioSequenceNumberStatsMap[streamStats._streamIdentifier];
streamStats._packetStreamStats = sequenceNumberStats.getStats();
streamStats._packetStreamWindowStats = sequenceNumberStats.getStatsForHistoryWindow();
} else {
streamStats._packetStreamStats = _incomingAvatarAudioSequenceNumberStats.getStats();
streamStats._packetStreamWindowStats = _incomingAvatarAudioSequenceNumberStats.getStatsForHistoryWindow();
}
const MovingMinMaxAvg<quint64>& timeGapStats = ringBuffer->getInterframeTimeGapStatsForStatsPacket();
streamStats._timeGapMin = timeGapStats.getMin();
streamStats._timeGapMax = timeGapStats.getMax();
@ -199,8 +208,18 @@ AudioStreamStats AudioMixerClientData::getAudioStreamStatsOfStream(const Positio
return streamStats;
}
void AudioMixerClientData::sendAudioStreamStatsPackets(const SharedNodePointer& destinationNode) const {
void AudioMixerClientData::sendAudioStreamStatsPackets(const SharedNodePointer& destinationNode) {
// have all the seq number stats of each audio stream push their current stats into their history,
// which moves that history window 1 second forward (since that's how long since the last stats were pushed into history)
_incomingAvatarAudioSequenceNumberStats.pushStatsToHistory();
QHash<QUuid, SequenceNumberStats>::Iterator i = _incomingInjectedAudioSequenceNumberStatsMap.begin();
QHash<QUuid, SequenceNumberStats>::Iterator end = _incomingInjectedAudioSequenceNumberStatsMap.end();
while (i != end) {
i.value().pushStatsToHistory();
i++;
}
char packet[MAX_PACKET_SIZE];
NodeList* nodeList = NodeList::getInstance();
@ -251,6 +270,23 @@ void AudioMixerClientData::sendAudioStreamStatsPackets(const SharedNodePointer&
QString AudioMixerClientData::getAudioStreamStatsString() const {
QString result;
AudioStreamStats streamStats = _downstreamAudioStreamStats;
result += "downstream.desired:" + QString::number(streamStats._ringBufferDesiredJitterBufferFrames)
+ " current: ?"
+ " available:" + QString::number(streamStats._ringBufferFramesAvailable)
+ " starves:" + QString::number(streamStats._ringBufferStarveCount)
+ " not mixed:" + QString::number(streamStats._ringBufferConsecutiveNotMixedCount)
+ " overflows:" + QString::number(streamStats._ringBufferOverflowCount)
+ " silents dropped: ?"
+ " lost %:" + QString::number(streamStats._packetStreamStats.getLostRate(), 'g', 2)
+ " lost % 30s:" + QString::number(streamStats._packetStreamWindowStats.getLostRate(), 'g', 2)
+ " min gap:" + QString::number(streamStats._timeGapMin)
+ " max gap:" + QString::number(streamStats._timeGapMax)
+ " avg gap:" + QString::number(streamStats._timeGapAverage, 'g', 2)
+ " min 30s gap:" + QString::number(streamStats._timeGapWindowMin)
+ " max 30s gap:" + QString::number(streamStats._timeGapWindowMax)
+ " avg 30s gap:" + QString::number(streamStats._timeGapWindowAverage, 'g', 2);
AvatarAudioRingBuffer* avatarRingBuffer = getAvatarAudioRingBuffer();
if (avatarRingBuffer) {
AudioStreamStats streamStats = getAudioStreamStatsOfStream(avatarRingBuffer);
@ -261,9 +297,8 @@ QString AudioMixerClientData::getAudioStreamStatsString() const {
+ " not mixed:" + QString::number(streamStats._ringBufferConsecutiveNotMixedCount)
+ " overflows:" + QString::number(streamStats._ringBufferOverflowCount)
+ " silents dropped:" + QString::number(streamStats._ringBufferSilentFramesDropped)
+ " early:" + QString::number(streamStats._packetStreamStats._numEarly)
+ " late:" + QString::number(streamStats._packetStreamStats._numLate)
+ " lost:" + QString::number(streamStats._packetStreamStats._numLost)
+ " lost %:" + QString::number(streamStats._packetStreamStats.getLostRate(), 'g', 2)
+ " lost % 30s:" + QString::number(streamStats._packetStreamWindowStats.getLostRate(), 'g', 2)
+ " min gap:" + QString::number(streamStats._timeGapMin)
+ " max gap:" + QString::number(streamStats._timeGapMax)
+ " avg gap:" + QString::number(streamStats._timeGapAverage, 'g', 2)
@ -277,16 +312,15 @@ QString AudioMixerClientData::getAudioStreamStatsString() const {
for (int i = 0; i < _ringBuffers.size(); i++) {
if (_ringBuffers[i]->getType() == PositionalAudioRingBuffer::Injector) {
AudioStreamStats streamStats = getAudioStreamStatsOfStream(_ringBuffers[i]);
result += "mic.desired:" + QString::number(streamStats._ringBufferDesiredJitterBufferFrames)
result += "inj.desired:" + QString::number(streamStats._ringBufferDesiredJitterBufferFrames)
+ " current:" + QString::number(streamStats._ringBufferCurrentJitterBufferFrames)
+ " available:" + QString::number(streamStats._ringBufferFramesAvailable)
+ " starves:" + QString::number(streamStats._ringBufferStarveCount)
+ " not mixed:" + QString::number(streamStats._ringBufferConsecutiveNotMixedCount)
+ " overflows:" + QString::number(streamStats._ringBufferOverflowCount)
+ " silents dropped:" + QString::number(streamStats._ringBufferSilentFramesDropped)
+ " early:" + QString::number(streamStats._packetStreamStats._numEarly)
+ " late:" + QString::number(streamStats._packetStreamStats._numLate)
+ " lost:" + QString::number(streamStats._packetStreamStats._numLost)
+ " lost %:" + QString::number(streamStats._packetStreamStats.getLostRate(), 'g', 2)
+ " lost % 30s:" + QString::number(streamStats._packetStreamWindowStats.getLostRate(), 'g', 2)
+ " min gap:" + QString::number(streamStats._timeGapMin)
+ " max gap:" + QString::number(streamStats._timeGapMax)
+ " avg gap:" + QString::number(streamStats._timeGapAverage, 'g', 2)

View file

@ -20,6 +20,9 @@
#include "AudioStreamStats.h"
#include "SequenceNumberStats.h"
const int INCOMING_SEQ_STATS_HISTORY_LENGTH_SECONDS = 30;
class AudioMixerClientData : public NodeData {
public:
AudioMixerClientData();
@ -35,7 +38,7 @@ public:
AudioStreamStats getAudioStreamStatsOfStream(const PositionalAudioRingBuffer* ringBuffer) const;
QString getAudioStreamStatsString() const;
void sendAudioStreamStatsPackets(const SharedNodePointer& destinationNode) const;
void sendAudioStreamStatsPackets(const SharedNodePointer& destinationNode);
void incrementOutgoingMixedAudioSequenceNumber() { _outgoingMixedAudioSequenceNumber++; }
quint16 getOutgoingSequenceNumber() const { return _outgoingMixedAudioSequenceNumber; }

View file

@ -33,7 +33,8 @@ public:
_ringBufferConsecutiveNotMixedCount(0),
_ringBufferOverflowCount(0),
_ringBufferSilentFramesDropped(0),
_packetStreamStats()
_packetStreamStats(),
_packetStreamWindowStats()
{}
PositionalAudioRingBuffer::Type _streamType;
@ -55,6 +56,7 @@ public:
quint32 _ringBufferSilentFramesDropped;
PacketStreamStats _packetStreamStats;
PacketStreamStats _packetStreamWindowStats;
};
#endif // hifi_AudioStreamStats_h

View file

@ -13,17 +13,19 @@
#include <limits>
SequenceNumberStats::SequenceNumberStats()
SequenceNumberStats::SequenceNumberStats(int statsHistoryLength)
: _lastReceived(std::numeric_limits<quint16>::max()),
_missingSet(),
_stats(),
_lastSenderUUID()
_lastSenderUUID(),
_statsHistory(statsHistoryLength)
{
}
void SequenceNumberStats::reset() {
_missingSet.clear();
_stats = PacketStreamStats();
_statsHistory.clear();
}
static const int UINT16_RANGE = std::numeric_limits<uint16_t>::max() + 1;
@ -168,3 +170,26 @@ void SequenceNumberStats::pruneMissingSet(const bool wantExtraDebugging) {
}
}
}
PacketStreamStats SequenceNumberStats::getStatsForHistoryWindow() const {
const PacketStreamStats* newestStats = _statsHistory.getNewestEntry();
const PacketStreamStats* oldestStats = _statsHistory.get(_statsHistory.getNumEntries() - 1);
// this catches cases where history is length 1 or 0 (both are NULL in case of 0)
if (newestStats == oldestStats) {
return PacketStreamStats();
}
// calculate difference between newest stats and oldest stats to get window stats
PacketStreamStats windowStats;
windowStats._numReceived = newestStats->_numReceived - oldestStats->_numReceived;
windowStats._numUnreasonable = newestStats->_numUnreasonable - oldestStats->_numUnreasonable;
windowStats._numEarly = newestStats->_numEarly - oldestStats->_numEarly;
windowStats._numLate = newestStats->_numLate - oldestStats->_numLate;
windowStats._numLost = newestStats->_numLost - oldestStats->_numLost;
windowStats._numRecovered = newestStats->_numRecovered - oldestStats->_numRecovered;
windowStats._numDuplicate = newestStats->_numDuplicate - oldestStats->_numDuplicate;
return windowStats;
}

View file

@ -13,6 +13,7 @@
#define hifi_SequenceNumberStats_h
#include "SharedUtil.h"
#include "RingBufferHistory.h"
#include <quuid.h>
const int MAX_REASONABLE_SEQUENCE_GAP = 1000;
@ -28,6 +29,14 @@ public:
_numRecovered(0),
_numDuplicate(0)
{}
float getUnreasonableRate() const { return (float)_numUnreasonable / _numReceived; }
float getNumEaryRate() const { return (float)_numEarly / _numReceived; }
float getLateRate() const { return (float)_numLate / _numReceived; }
float getLostRate() const { return (float)_numLost / _numReceived; }
float getRecoveredRate() const { return (float)_numRecovered / _numReceived; }
float getDuplicateRate() const { return (float)_numDuplicate / _numReceived; }
quint32 _numReceived;
quint32 _numUnreasonable;
quint32 _numEarly;
@ -39,11 +48,12 @@ public:
class SequenceNumberStats {
public:
SequenceNumberStats();
SequenceNumberStats(int statsHistoryLength = 0);
void reset();
void sequenceNumberReceived(quint16 incoming, QUuid senderUUID = QUuid(), const bool wantExtraDebugging = false);
void pruneMissingSet(const bool wantExtraDebugging = false);
void pushStatsToHistory() { _statsHistory.insert(_stats); }
quint32 getNumReceived() const { return _stats._numReceived; }
quint32 getNumUnreasonable() const { return _stats._numUnreasonable; }
@ -54,6 +64,7 @@ public:
quint32 getNumRecovered() const { return _stats._numRecovered; }
quint32 getNumDuplicate() const { return _stats._numDuplicate; }
const PacketStreamStats& getStats() const { return _stats; }
PacketStreamStats getStatsForHistoryWindow() const;
const QSet<quint16>& getMissingSet() const { return _missingSet; }
private:
@ -63,6 +74,8 @@ private:
PacketStreamStats _stats;
QUuid _lastSenderUUID;
RingBufferHistory<PacketStreamStats> _statsHistory;
};
#endif // hifi_SequenceNumberStats_h

View file

@ -64,11 +64,11 @@ public:
}
const T* getNewestEntry() const {
return &_buffer[_newestEntryAtIndex];
return _numEntries == 0 ? NULL : &_buffer[_newestEntryAtIndex];
}
T* getNewestEntry() {
return &_buffer[_newestEntryAtIndex];
return _numEntries == 0 ? NULL : &_buffer[_newestEntryAtIndex];
}
int getCapacity() const { return _capacity; }