mirror of
https://github.com/overte-org/overte.git
synced 2025-04-20 03:24:00 +02:00
added window PacketStreamStats to AudioStreamStats
This commit is contained in:
parent
b4c9e51011
commit
25f4f63a1e
8 changed files with 97 additions and 21 deletions
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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; }
|
||||
|
|
Loading…
Reference in a new issue