From 14cf5b04b53f27d39584b910206b76548c097490 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 24 Oct 2013 10:33:19 -0700 Subject: [PATCH 1/2] added suppression of duplicate voxel packets to save on bit/packet rate --- .../src/VoxelNodeData.cpp | 49 +++++++++++++++++++ .../voxel-server-library/src/VoxelNodeData.h | 10 ++++ .../src/VoxelSendThread.cpp | 10 +++- 3 files changed, 67 insertions(+), 2 deletions(-) diff --git a/libraries/voxel-server-library/src/VoxelNodeData.cpp b/libraries/voxel-server-library/src/VoxelNodeData.cpp index 1995dcc867..951888498a 100644 --- a/libraries/voxel-server-library/src/VoxelNodeData.cpp +++ b/libraries/voxel-server-library/src/VoxelNodeData.cpp @@ -27,6 +27,9 @@ VoxelNodeData::VoxelNodeData(Node* owningNode) : { _voxelPacket = new unsigned char[MAX_VOXEL_PACKET_SIZE]; _voxelPacketAt = _voxelPacket; + _lastVoxelPacket = new unsigned char[MAX_VOXEL_PACKET_SIZE]; + _lastVoxelPacketLength = 0; + _duplicatePacketCount = 0; resetVoxelPacket(); } @@ -37,9 +40,55 @@ void VoxelNodeData::initializeVoxelSendThread(VoxelServer* voxelServer) { _voxelSendThread->initialize(true); } +bool VoxelNodeData::packetIsDuplicate() const { + if (_lastVoxelPacketLength == getPacketLength()) { + return memcmp(_lastVoxelPacket, _voxelPacket, getPacketLength()) == 0; + } + return false; +} +bool VoxelNodeData::shouldSuppressDuplicatePacket() { + bool shouldSuppress = false; // assume we won't suppress + + // only consider duplicate packets + if (packetIsDuplicate()) { + _duplicatePacketCount++; + + // If this is the first suppressed packet, remember our time... + if (_duplicatePacketCount == 1) { + _firstSuppressedPacket = usecTimestampNow(); + } + + // How long has it been since we've sent one, if we're still under our max time, then keep considering + // this packet for suppression + uint64_t now = usecTimestampNow(); + long sinceFirstSuppressedPacket = now - _firstSuppressedPacket; + const long MAX_TIME_BETWEEN_DUPLICATE_PACKETS = 1000 * 1000; // 1 second. + + if (sinceFirstSuppressedPacket < MAX_TIME_BETWEEN_DUPLICATE_PACKETS) { + // Finally, if we know we've sent at least one duplicate out, then suppress the rest... + if (_duplicatePacketCount > 1) { + shouldSuppress = true; + } + } else { + // Reset our count, we've reached our maximum time. + _duplicatePacketCount = 0; + } + } else { + // Reset our count, it wasn't a duplicate + _duplicatePacketCount = 0; + } + return shouldSuppress; +} void VoxelNodeData::resetVoxelPacket() { + // Whenever we call this, we will keep a copy of the last packet, so we can determine if the last packet has + // changed since we last reset it. Since we know that no two packets can ever be identical without being the same + // scene information, (e.g. the root node packet of a static scene), we can use this as a strategy for reducing + // packet send rate. + _lastVoxelPacketLength = getPacketLength(); + memcpy(_lastVoxelPacket, _voxelPacket, _lastVoxelPacketLength); + // If we're moving, and the client asked for low res, then we force monochrome, otherwise, use // the clients requested color state. _currentPacketIsColor = (LOW_RES_MONO && getWantLowResMoving() && _viewFrustumChanging) ? false : getWantColor(); diff --git a/libraries/voxel-server-library/src/VoxelNodeData.h b/libraries/voxel-server-library/src/VoxelNodeData.h index 85ebe2ebb7..0a8412f8e8 100644 --- a/libraries/voxel-server-library/src/VoxelNodeData.h +++ b/libraries/voxel-server-library/src/VoxelNodeData.h @@ -33,6 +33,10 @@ public: const unsigned char* getPacket() const { return _voxelPacket; } int getPacketLength() const { return (MAX_VOXEL_PACKET_SIZE - _voxelPacketAvailableBytes); } bool isPacketWaiting() const { return _voxelPacketWaiting; } + + bool packetIsDuplicate() const; + bool shouldSuppressDuplicatePacket(); + int getAvailable() const { return _voxelPacketAvailableBytes; } int getMaxSearchLevel() const { return _maxSearchLevel; }; void resetMaxSearchLevel() { _maxSearchLevel = 1; }; @@ -78,6 +82,12 @@ private: unsigned char* _voxelPacketAt; int _voxelPacketAvailableBytes; bool _voxelPacketWaiting; + + unsigned char* _lastVoxelPacket; + int _lastVoxelPacketLength; + int _duplicatePacketCount; + uint64_t _firstSuppressedPacket; + int _maxSearchLevel; int _maxLevelReachedInLastSearch; ViewFrustum _currentViewFrustum; diff --git a/libraries/voxel-server-library/src/VoxelSendThread.cpp b/libraries/voxel-server-library/src/VoxelSendThread.cpp index 6fbf034455..99afafae19 100644 --- a/libraries/voxel-server-library/src/VoxelSendThread.cpp +++ b/libraries/voxel-server-library/src/VoxelSendThread.cpp @@ -59,6 +59,14 @@ bool VoxelSendThread::process() { void VoxelSendThread::handlePacketSend(Node* node, VoxelNodeData* nodeData, int& trueBytesSent, int& truePacketsSent) { + // Here's where we check to see if this packet is a duplicate of the last packet. If it is, we will silently + // obscure the packet and not send it. This allows the callers and upper level logic to not need to know about + // this rate control savings. + if (nodeData->shouldSuppressDuplicatePacket()) { + printf ("handlePacketSend() silently ate the last packet which was a duplicate...\n"); + return; // without sending... + } + // If we've got a stats message ready to send, then see if we can piggyback them together if (nodeData->stats.isReadyToSend()) { // Send the stats message to the client @@ -254,13 +262,11 @@ void VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* no } else { handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent); packetsSentThisInterval++; - nodeData->resetVoxelPacket(); nodeData->writeToPacket(_tempOutputBuffer, bytesWritten); } } else { if (nodeData->isPacketWaiting()) { handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent); - nodeData->resetVoxelPacket(); } packetsSentThisInterval = _myServer->getPacketsPerClientPerInterval(); // done for now, no nodes left } From 9cd04af1aedac0e2f1705385642fa7d5bce122dc Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 24 Oct 2013 10:48:17 -0700 Subject: [PATCH 2/2] removed debug --- libraries/voxel-server-library/src/VoxelSendThread.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/voxel-server-library/src/VoxelSendThread.cpp b/libraries/voxel-server-library/src/VoxelSendThread.cpp index 99afafae19..1966bc7952 100644 --- a/libraries/voxel-server-library/src/VoxelSendThread.cpp +++ b/libraries/voxel-server-library/src/VoxelSendThread.cpp @@ -63,7 +63,6 @@ void VoxelSendThread::handlePacketSend(Node* node, VoxelNodeData* nodeData, int& // obscure the packet and not send it. This allows the callers and upper level logic to not need to know about // this rate control savings. if (nodeData->shouldSuppressDuplicatePacket()) { - printf ("handlePacketSend() silently ate the last packet which was a duplicate...\n"); return; // without sending... }