diff --git a/assignment-client/src/audio/AudioMixerClientData.cpp b/assignment-client/src/audio/AudioMixerClientData.cpp index 9b14ecfd19..f6437f9c97 100644 --- a/assignment-client/src/audio/AudioMixerClientData.cpp +++ b/assignment-client/src/audio/AudioMixerClientData.cpp @@ -101,8 +101,7 @@ int AudioMixerClientData::parseData(const QByteArray& packet) { if (!matchingInjectedRingBuffer) { // we don't have a matching injected audio ring buffer, so add it - matchingInjectedRingBuffer = new InjectedAudioRingBuffer(streamIdentifier, - AudioMixer::getUseDynamicJitterBuffers()); + matchingInjectedRingBuffer = new InjectedAudioRingBuffer(streamIdentifier, AudioMixer::getUseDynamicJitterBuffers()); _ringBuffers.push_back(matchingInjectedRingBuffer); } diff --git a/assignment-client/src/octree/OctreeInboundPacketProcessor.cpp b/assignment-client/src/octree/OctreeInboundPacketProcessor.cpp index 3d2ca6ddc3..7716f9e2aa 100644 --- a/assignment-client/src/octree/OctreeInboundPacketProcessor.cpp +++ b/assignment-client/src/octree/OctreeInboundPacketProcessor.cpp @@ -216,9 +216,13 @@ int OctreeInboundPacketProcessor::sendNackPackets() { } const SharedNodePointer& destinationNode = NodeList::getInstance()->getNodeHash().value(nodeUUID); - const QSet& missingSequenceNumbers = nodeStats.getIncomingEditSequenceNumberStats().getMissingSet(); + + // retrieve sequence number stats of node, prune its missing set + SequenceNumberStats& sequenceNumberStats = nodeStats.getIncomingEditSequenceNumberStats(); + sequenceNumberStats.pruneMissingSet(); // construct nack packet(s) for this node + const QSet& missingSequenceNumbers = sequenceNumberStats.getMissingSet(); int numSequenceNumbersAvailable = missingSequenceNumbers.size(); QSet::const_iterator missingSequenceNumberIterator = missingSequenceNumbers.constBegin(); while (numSequenceNumbersAvailable > 0) { diff --git a/assignment-client/src/octree/OctreeInboundPacketProcessor.h b/assignment-client/src/octree/OctreeInboundPacketProcessor.h index 960282384b..2fb83123c4 100644 --- a/assignment-client/src/octree/OctreeInboundPacketProcessor.h +++ b/assignment-client/src/octree/OctreeInboundPacketProcessor.h @@ -35,6 +35,7 @@ public: { return _totalElementsInPacket == 0 ? 0 : _totalLockWaitTime / _totalElementsInPacket; } const SequenceNumberStats& getIncomingEditSequenceNumberStats() const { return _incomingEditSequenceNumberStats; } + SequenceNumberStats& getIncomingEditSequenceNumberStats() { return _incomingEditSequenceNumberStats; } void trackInboundPacket(unsigned short int incomingSequence, quint64 transitTime, int editsInPacket, quint64 processTime, quint64 lockWaitTime); diff --git a/assignment-client/src/octree/OctreeQueryNode.cpp b/assignment-client/src/octree/OctreeQueryNode.cpp index 3531c3f9cb..11783fe7d2 100644 --- a/assignment-client/src/octree/OctreeQueryNode.cpp +++ b/assignment-client/src/octree/OctreeQueryNode.cpp @@ -42,7 +42,7 @@ OctreeQueryNode::OctreeQueryNode() : _lastRootTimestamp(0), _myPacketType(PacketTypeUnknown), _isShuttingDown(false), - _sentPacketHistory(1000) + _sentPacketHistory() { } diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index b062c231bd..2733d1aea8 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2184,11 +2184,11 @@ int Application::sendNackPackets() { _octreeSceneStatsLock.unlock(); continue; } - OctreeSceneStats& stats = _octreeServerSceneStats[nodeUUID]; - // make copy of missing sequence numbers from stats - const QSet missingSequenceNumbers = - stats.getIncomingOctreeSequenceNumberStats().getMissingSet(); + // get sequence number stats of node, prune its missing set, and make a copy of the missing set + SequenceNumberStats& sequenceNumberStats = _octreeServerSceneStats[nodeUUID].getIncomingOctreeSequenceNumberStats(); + sequenceNumberStats.pruneMissingSet(); + const QSet missingSequenceNumbers = sequenceNumberStats.getMissingSet(); _octreeSceneStatsLock.unlock(); diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index df9df878bb..6bbd769d25 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -67,7 +67,7 @@ Audio::Audio(int16_t initialJitterBufferSamples, QObject* parent) : _proceduralAudioOutput(NULL), _proceduralOutputDevice(NULL), _inputRingBuffer(0), - _ringBuffer(NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL), + _ringBuffer(NETWORK_BUFFER_LENGTH_SAMPLES_STEREO), _isStereoInput(false), _averagedLatency(0.0), _measuredJitter(0), @@ -93,7 +93,7 @@ Audio::Audio(int16_t initialJitterBufferSamples, QObject* parent) : _processSpatialAudio(false), _spatialAudioStart(0), _spatialAudioFinish(0), - _spatialAudioRingBuffer(NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL, true), // random access mode + _spatialAudioRingBuffer(NETWORK_BUFFER_LENGTH_SAMPLES_STEREO, true), // random access mode _scopeEnabled(false), _scopeEnabledPause(false), _scopeInputOffset(0), diff --git a/interface/src/DatagramProcessor.cpp b/interface/src/DatagramProcessor.cpp index a159af7be5..6c39994bf3 100644 --- a/interface/src/DatagramProcessor.cpp +++ b/interface/src/DatagramProcessor.cpp @@ -149,13 +149,19 @@ void DatagramProcessor::processDatagrams() { break; } case PacketTypeVoxelEditNack: - application->_voxelEditSender.processNackPacket(incomingPacket); + if (!Menu::getInstance()->isOptionChecked(MenuOption::DisableNackPackets)) { + application->_voxelEditSender.processNackPacket(incomingPacket); + } break; case PacketTypeParticleEditNack: - application->_particleEditSender.processNackPacket(incomingPacket); + if (!Menu::getInstance()->isOptionChecked(MenuOption::DisableNackPackets)) { + application->_particleEditSender.processNackPacket(incomingPacket); + } break; case PacketTypeModelEditNack: - application->_modelEditSender.processNackPacket(incomingPacket); + if (!Menu::getInstance()->isOptionChecked(MenuOption::DisableNackPackets)) { + application->_modelEditSender.processNackPacket(incomingPacket); + } break; default: nodeList->processNodeData(senderSockAddr, incomingPacket); diff --git a/libraries/audio/src/AudioRingBuffer.cpp b/libraries/audio/src/AudioRingBuffer.cpp index 7937a925a8..0defa2ea33 100644 --- a/libraries/audio/src/AudioRingBuffer.cpp +++ b/libraries/audio/src/AudioRingBuffer.cpp @@ -19,10 +19,11 @@ #include "AudioRingBuffer.h" -AudioRingBuffer::AudioRingBuffer(int numFrameSamples, bool randomAccessMode) : +AudioRingBuffer::AudioRingBuffer(int numFrameSamples, bool randomAccessMode, int numFramesCapacity) : NodeData(), _overflowCount(0), - _sampleCapacity(numFrameSamples * RING_BUFFER_LENGTH_FRAMES), + _frameCapacity(numFramesCapacity), + _sampleCapacity(numFrameSamples * numFramesCapacity), _isFull(false), _numFrameSamples(numFrameSamples), _isStarved(true), @@ -48,6 +49,8 @@ AudioRingBuffer::~AudioRingBuffer() { } void AudioRingBuffer::reset() { + _overflowCount = 0; + _isFull = false; _endOfLastWrite = _buffer; _nextOutput = _buffer; _isStarved = true; @@ -55,13 +58,13 @@ void AudioRingBuffer::reset() { void AudioRingBuffer::resizeForFrameSize(int numFrameSamples) { delete[] _buffer; - _sampleCapacity = numFrameSamples * RING_BUFFER_LENGTH_FRAMES; + _sampleCapacity = numFrameSamples * _frameCapacity; + _numFrameSamples = numFrameSamples; _buffer = new int16_t[_sampleCapacity]; if (_randomAccessMode) { memset(_buffer, 0, _sampleCapacity * sizeof(int16_t)); } - _nextOutput = _buffer; - _endOfLastWrite = _buffer; + reset(); } int AudioRingBuffer::parseData(const QByteArray& packet) { diff --git a/libraries/audio/src/AudioRingBuffer.h b/libraries/audio/src/AudioRingBuffer.h index 80a2abeba4..047db70693 100644 --- a/libraries/audio/src/AudioRingBuffer.h +++ b/libraries/audio/src/AudioRingBuffer.h @@ -31,15 +31,15 @@ const int NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL = NETWORK_BUFFER_LENGTH_BYTE const unsigned int BUFFER_SEND_INTERVAL_USECS = floorf((NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL / (float) SAMPLE_RATE) * 1000 * 1000); -const short RING_BUFFER_LENGTH_FRAMES = 10; - const int MAX_SAMPLE_VALUE = std::numeric_limits::max(); const int MIN_SAMPLE_VALUE = std::numeric_limits::min(); +const int DEFAULT_RING_BUFFER_FRAME_CAPACITY = 10; + class AudioRingBuffer : public NodeData { Q_OBJECT public: - AudioRingBuffer(int numFrameSamples, bool randomAccessMode = false); + AudioRingBuffer(int numFrameSamples, bool randomAccessMode = false, int numFramesCapacity = DEFAULT_RING_BUFFER_FRAME_CAPACITY); ~AudioRingBuffer(); void reset(); @@ -84,6 +84,7 @@ protected: int _overflowCount; /// how many times has the ring buffer has overwritten old data + int _frameCapacity; int _sampleCapacity; bool _isFull; int _numFrameSamples; diff --git a/libraries/audio/src/InjectedAudioRingBuffer.cpp b/libraries/audio/src/InjectedAudioRingBuffer.cpp index 0d7cea356b..c84fe173c9 100644 --- a/libraries/audio/src/InjectedAudioRingBuffer.cpp +++ b/libraries/audio/src/InjectedAudioRingBuffer.cpp @@ -20,7 +20,7 @@ #include "InjectedAudioRingBuffer.h" InjectedAudioRingBuffer::InjectedAudioRingBuffer(const QUuid& streamIdentifier, bool dynamicJitterBuffer) : - PositionalAudioRingBuffer(PositionalAudioRingBuffer::Injector, /* isStereo=*/ false , dynamicJitterBuffer), + PositionalAudioRingBuffer(PositionalAudioRingBuffer::Injector, false, dynamicJitterBuffer), _streamIdentifier(streamIdentifier), _radius(0.0f), _attenuationRatio(0) diff --git a/libraries/audio/src/PositionalAudioRingBuffer.cpp b/libraries/audio/src/PositionalAudioRingBuffer.cpp index e11d73358c..0fe75f1239 100644 --- a/libraries/audio/src/PositionalAudioRingBuffer.cpp +++ b/libraries/audio/src/PositionalAudioRingBuffer.cpp @@ -85,10 +85,10 @@ quint64 InterframeTimeGapStats::getWindowMaxGap() { } -PositionalAudioRingBuffer::PositionalAudioRingBuffer(PositionalAudioRingBuffer::Type type, - bool isStereo, bool dynamicJitterBuffers) : +PositionalAudioRingBuffer::PositionalAudioRingBuffer(PositionalAudioRingBuffer::Type type, bool isStereo, bool dynamicJitterBuffers) : - AudioRingBuffer(isStereo ? NETWORK_BUFFER_LENGTH_SAMPLES_STEREO : NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL), + AudioRingBuffer(isStereo ? NETWORK_BUFFER_LENGTH_SAMPLES_STEREO : NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL, + false, AUDIOMIXER_INBOUND_RING_BUFFER_FRAME_CAPACITY), _type(type), _position(0.0f, 0.0f, 0.0f), _orientation(0.0f, 0.0f, 0.0f, 0.0f), @@ -98,7 +98,7 @@ PositionalAudioRingBuffer::PositionalAudioRingBuffer(PositionalAudioRingBuffer:: _isStereo(isStereo), _listenerUnattenuatedZone(NULL), _desiredJitterBufferFrames(1), - _currentJitterBufferFrames(0), + _currentJitterBufferFrames(-1), _dynamicJitterBuffers(dynamicJitterBuffers) { } @@ -216,8 +216,8 @@ bool PositionalAudioRingBuffer::shouldBeAddedToMix() { // if the buffer doesn't have a full frame of samples to take for mixing, it is starved _isStarved = true; - // set to 0 to indicate the jitter buffer is starved - _currentJitterBufferFrames = 0; + // set to -1 to indicate the jitter buffer is starved + _currentJitterBufferFrames = -1; // reset our _shouldOutputStarveDebug to true so the next is printed _shouldOutputStarveDebug = true; @@ -261,7 +261,7 @@ void PositionalAudioRingBuffer::updateDesiredJitterBufferFrames() { if (_desiredJitterBufferFrames < 1) { _desiredJitterBufferFrames = 1; } - const int maxDesired = RING_BUFFER_LENGTH_FRAMES - 1; + const int maxDesired = _frameCapacity - 1; if (_desiredJitterBufferFrames > maxDesired) { _desiredJitterBufferFrames = maxDesired; } diff --git a/libraries/audio/src/PositionalAudioRingBuffer.h b/libraries/audio/src/PositionalAudioRingBuffer.h index b204dc766b..0322afb47b 100644 --- a/libraries/audio/src/PositionalAudioRingBuffer.h +++ b/libraries/audio/src/PositionalAudioRingBuffer.h @@ -43,6 +43,8 @@ private: bool _newWindowMaxGapAvailable; }; +const int AUDIOMIXER_INBOUND_RING_BUFFER_FRAME_CAPACITY = 100; + class PositionalAudioRingBuffer : public AudioRingBuffer { public: enum Type { @@ -103,6 +105,11 @@ protected: int _desiredJitterBufferFrames; int _currentJitterBufferFrames; bool _dynamicJitterBuffers; + + // extra stats + int _starveCount; + int _silentFramesDropped; + }; #endif // hifi_PositionalAudioRingBuffer_h diff --git a/libraries/networking/src/SentPacketHistory.h b/libraries/networking/src/SentPacketHistory.h index 53a6919c42..325f973f7e 100644 --- a/libraries/networking/src/SentPacketHistory.h +++ b/libraries/networking/src/SentPacketHistory.h @@ -15,10 +15,12 @@ #include #include +#include "SequenceNumberStats.h" + class SentPacketHistory { public: - SentPacketHistory(int size = 1000); + SentPacketHistory(int size = MAX_REASONABLE_SEQUENCE_GAP); void packetSent(uint16_t sequenceNumber, const QByteArray& packet); const QByteArray* getPacket(uint16_t sequenceNumber) const; diff --git a/libraries/networking/src/SequenceNumberStats.cpp b/libraries/networking/src/SequenceNumberStats.cpp index 15d3c0542e..3f696a522b 100644 --- a/libraries/networking/src/SequenceNumberStats.cpp +++ b/libraries/networking/src/SequenceNumberStats.cpp @@ -39,7 +39,6 @@ void SequenceNumberStats::reset() { } static const int UINT16_RANGE = std::numeric_limits::max() + 1; -static const int MAX_REASONABLE_SEQUENCE_GAP = 1000; // this must be less than UINT16_RANGE / 2 for rollover handling to work void SequenceNumberStats::sequenceNumberReceived(quint16 incoming, QUuid senderUUID, const bool wantExtraDebugging) { @@ -95,6 +94,7 @@ void SequenceNumberStats::sequenceNumberReceived(quint16 incoming, QUuid senderU _numEarly++; _numLost += (incomingInt - expectedInt); + _lastReceived = incoming; // add all sequence numbers that were skipped to the missing sequence numbers list for (int missingInt = expectedInt; missingInt < incomingInt; missingInt++) { @@ -106,14 +106,14 @@ void SequenceNumberStats::sequenceNumberReceived(quint16 incoming, QUuid senderU if (_missingSet.size() > MAX_REASONABLE_SEQUENCE_GAP) { pruneMissingSet(wantExtraDebugging); } - - _lastReceived = incoming; } else { // late if (wantExtraDebugging) { qDebug() << "this packet is later than expected..."; } _numLate++; + // do not update _lastReceived; it shouldn't become smaller + // remove this from missing sequence number if it's in there if (_missingSet.remove(incoming)) { if (wantExtraDebugging) { @@ -127,8 +127,6 @@ void SequenceNumberStats::sequenceNumberReceived(quint16 incoming, QUuid senderU } _numDuplicate++; } - - // do not update _incomingLastSequence; it shouldn't become smaller } } } diff --git a/libraries/networking/src/SequenceNumberStats.h b/libraries/networking/src/SequenceNumberStats.h index b2561552ef..88c8748b03 100644 --- a/libraries/networking/src/SequenceNumberStats.h +++ b/libraries/networking/src/SequenceNumberStats.h @@ -15,13 +15,15 @@ #include "SharedUtil.h" #include +const int MAX_REASONABLE_SEQUENCE_GAP = 1000; + class SequenceNumberStats { public: SequenceNumberStats(); void reset(); - void sequenceNumberReceived(quint16 incoming, QUuid senderUUID = QUuid(), const bool wantExtraDebugging = false); + void pruneMissingSet(const bool wantExtraDebugging = false); quint32 getNumReceived() const { return _numReceived; } quint32 getNumUnreasonable() const { return _numUnreasonable; } @@ -34,8 +36,6 @@ public: const QSet& getMissingSet() const { return _missingSet; } private: - void pruneMissingSet(const bool wantExtraDebugging); - quint16 _lastReceived; QSet _missingSet; diff --git a/libraries/octree/src/OctreeSceneStats.h b/libraries/octree/src/OctreeSceneStats.h index d7b65c63be..cefaaa5764 100644 --- a/libraries/octree/src/OctreeSceneStats.h +++ b/libraries/octree/src/OctreeSceneStats.h @@ -168,6 +168,7 @@ public: float getIncomingFlightTimeAverage() { return _incomingFlightTimeAverage.getAverage(); } const SequenceNumberStats& getIncomingOctreeSequenceNumberStats() const { return _incomingOctreeSequenceNumberStats; } + SequenceNumberStats& getIncomingOctreeSequenceNumberStats() { return _incomingOctreeSequenceNumberStats; } private: diff --git a/tests/audio/src/AudioRingBufferTests.cpp b/tests/audio/src/AudioRingBufferTests.cpp index 506e81e13e..b9ed596e52 100644 --- a/tests/audio/src/AudioRingBufferTests.cpp +++ b/tests/audio/src/AudioRingBufferTests.cpp @@ -29,7 +29,7 @@ void AudioRingBufferTests::runAllTests() { int readIndexAt; - AudioRingBuffer ringBuffer(10); // makes buffer of 100 int16_t samples + AudioRingBuffer ringBuffer(10, false, 10); // makes buffer of 100 int16_t samples for (int T = 0; T < 300; T++) { writeIndexAt = 0; diff --git a/tests/networking/src/SequenceNumberStatsTests.cpp b/tests/networking/src/SequenceNumberStatsTests.cpp index 62651eaa6f..de487267e0 100644 --- a/tests/networking/src/SequenceNumberStatsTests.cpp +++ b/tests/networking/src/SequenceNumberStatsTests.cpp @@ -115,6 +115,11 @@ void SequenceNumberStatsTests::earlyLateTest() { } } stats.reset(); + numSent = 0; + numEarly = 0; + numLate = 0; + numLost = 0; + numRecovered = 0; } } @@ -203,6 +208,11 @@ void SequenceNumberStatsTests::duplicateTest() { } } stats.reset(); + numSent = 0; + numDuplicate = 0; + numEarly = 0; + numLate = 0; + numLost = 0; } } @@ -263,5 +273,8 @@ void SequenceNumberStatsTests::pruneTest() { } } stats.reset(); + numSent = 0; + numEarly = 0; + numLost = 0; } }