Merge pull request #1111 from ZappoMan/rate_control

added suppression of duplicate voxel packets to save on bit/packet rate
This commit is contained in:
Philip Rosedale 2013-10-24 10:57:44 -07:00
commit ba5db325aa
3 changed files with 66 additions and 2 deletions

View file

@ -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();

View file

@ -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;

View file

@ -59,6 +59,13 @@ 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()) {
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 +261,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
}