diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 524b5ccd09..345ede0274 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3339,12 +3339,6 @@ void* Application::networkReceive(void* args) { if (packetVersionMatch(app->_incomingPacket)) { // only process this packet if we have a match on the packet version switch (app->_incomingPacket[0]) { - case PACKET_TYPE_VOXEL_STATS:{ - VoxelSceneStats stats; - int statsMessageLength = stats.unpackFromMessage(app->_incomingPacket, bytesReceived); - stats.printDebugDetails(); - break; - } case PACKET_TYPE_TRANSMITTER_DATA_V2: // V2 = IOS transmitter app app->_myTransmitter.processIncomingData(app->_incomingPacket, bytesReceived); @@ -3357,16 +3351,39 @@ void* Application::networkReceive(void* args) { case PACKET_TYPE_VOXEL_DATA_MONOCHROME: case PACKET_TYPE_Z_COMMAND: case PACKET_TYPE_ERASE_VOXEL: + case PACKET_TYPE_VOXEL_STATS: case PACKET_TYPE_ENVIRONMENT_DATA: { + + unsigned char* messageData = app->_incomingPacket; + ssize_t messageLength = bytesReceived; + + // note: PACKET_TYPE_VOXEL_STATS can have PACKET_TYPE_VOXEL_DATA or PACKET_TYPE_VOXEL_DATA_MONOCHROME + // immediately following them inside the same packet. So, we process the PACKET_TYPE_VOXEL_STATS first + // then process any remaining bytes as if it was another packet + if (messageData[0] == PACKET_TYPE_VOXEL_STATS) { + VoxelSceneStats stats; + int statsMessageLength = stats.unpackFromMessage(messageData, messageLength); + stats.printDebugDetails(); + if (messageLength > statsMessageLength) { + messageData += statsMessageLength; + messageLength -= statsMessageLength; + if (!packetVersionMatch(messageData)) { + break; // bail since piggyback data doesn't match our versioning + } + } else { + break; // bail since no piggyback data + } + } // fall through to piggyback message + if (app->_renderVoxels->isChecked()) { Node* voxelServer = NodeList::getInstance()->soloNodeOfType(NODE_TYPE_VOXEL_SERVER); if (voxelServer) { voxelServer->lock(); - if (app->_incomingPacket[0] == PACKET_TYPE_ENVIRONMENT_DATA) { - app->_environment.parseData(&senderAddress, app->_incomingPacket, bytesReceived); + if (messageData[0] == PACKET_TYPE_ENVIRONMENT_DATA) { + app->_environment.parseData(&senderAddress, messageData, messageLength); } else { - app->_voxels.parseData(app->_incomingPacket, bytesReceived); + app->_voxels.parseData(messageData, messageLength); } voxelServer->unlock(); diff --git a/libraries/voxels/src/VoxelSceneStats.cpp b/libraries/voxels/src/VoxelSceneStats.cpp index 0368c530ec..ab25b725bb 100644 --- a/libraries/voxels/src/VoxelSceneStats.cpp +++ b/libraries/voxels/src/VoxelSceneStats.cpp @@ -14,6 +14,7 @@ VoxelSceneStats::VoxelSceneStats() { reset(); + _readyToSend = false; } VoxelSceneStats::~VoxelSceneStats() { @@ -29,6 +30,9 @@ void VoxelSceneStats::sceneStarted(bool fullScene, bool moving) { void VoxelSceneStats::sceneCompleted() { _end = usecTimestampNow(); _elapsed = _end - _start; + + _statsMessageLength = packIntoMessage(_statsMessage, sizeof(_statsMessage)); + _readyToSend = true; } void VoxelSceneStats::encodeStarted() { diff --git a/libraries/voxels/src/VoxelSceneStats.h b/libraries/voxels/src/VoxelSceneStats.h index 93146ffa88..05545f3320 100644 --- a/libraries/voxels/src/VoxelSceneStats.h +++ b/libraries/voxels/src/VoxelSceneStats.h @@ -10,6 +10,7 @@ #define __hifi__VoxelSceneStats__ #include +#include class VoxelNode; @@ -20,6 +21,7 @@ public: void reset(); void sceneStarted(bool fullScene, bool moving); void sceneCompleted(); + void printDebugDetails(); void packetSent(int bytes); @@ -41,8 +43,18 @@ public: int packIntoMessage(unsigned char* destinationBuffer, int availableBytes); int unpackFromMessage(unsigned char* sourceBuffer, int availableBytes); + + bool readyToSend() const { return _readyToSend; } + void markAsSent() { _readyToSend = false; } + unsigned char* getStatsMessage() { return &_statsMessage[0]; } + int getStatsMessageLength() const { return _statsMessageLength; } + private: + bool _readyToSend; + unsigned char _statsMessage[MAX_PACKET_SIZE]; + int _statsMessageLength; + // scene timing data in usecs uint64_t _start; uint64_t _end; diff --git a/voxel-server/src/main.cpp b/voxel-server/src/main.cpp index 5ae2874a34..6244ee190d 100644 --- a/voxel-server/src/main.cpp +++ b/voxel-server/src/main.cpp @@ -112,6 +112,44 @@ void eraseVoxelTreeAndCleanupNodeVisitData() { pthread_mutex_t treeLock; +void handlePacketSend(NodeList* nodeList, + NodeList::iterator& node, + VoxelNodeData* nodeData, + int& trueBytesSent, int& truePacketsSent) { + // If we've got a stats message ready to send, then see if we can piggyback them together + if (nodeData->stats.readyToSend()) { + // Send the stats message to the client + unsigned char* statsMessage = nodeData->stats.getStatsMessage(); + int statsMessageLength = nodeData->stats.getStatsMessageLength(); + + // If the size of the stats message and the voxel message will fit in a packet, then piggyback them + if (nodeData->getPacketLength() + statsMessageLength < MAX_PACKET_SIZE) { + + // copy voxel message to back of stats message + memcpy(statsMessage + statsMessageLength, nodeData->getPacket(), nodeData->getPacketLength()); + statsMessageLength += nodeData->getPacketLength(); + + // actually send it + nodeList->getNodeSocket()->send(node->getActiveSocket(), statsMessage, statsMessageLength); + } else { + // not enough room in the packet, send two packets + nodeList->getNodeSocket()->send(node->getActiveSocket(), statsMessage, statsMessageLength); + nodeList->getNodeSocket()->send(node->getActiveSocket(), + nodeData->getPacket(), nodeData->getPacketLength()); + } + } else { + // just send the voxel packet + nodeList->getNodeSocket()->send(node->getActiveSocket(), + nodeData->getPacket(), nodeData->getPacketLength()); + } + // remember to track our stats + nodeData->stats.packetSent(nodeData->getPacketLength()); + trueBytesSent += nodeData->getPacketLength(); + truePacketsSent++; + nodeData->resetVoxelPacket(); +} + + // Version of voxel distributor that sends the deepest LOD level at once void deepestLevelVoxelDistributor(NodeList* nodeList, NodeList::iterator& node, @@ -142,12 +180,9 @@ void deepestLevelVoxelDistributor(NodeList* nodeList, printf("wantColor=%s --- SENDING PARTIAL PACKET! nodeData->getCurrentPacketIsColor()=%s\n", debug::valueOf(wantColor), debug::valueOf(nodeData->getCurrentPacketIsColor())); } - nodeList->getNodeSocket()->send(node->getActiveSocket(), - nodeData->getPacket(), nodeData->getPacketLength()); - nodeData->stats.packetSent(nodeData->getPacketLength()); - trueBytesSent += nodeData->getPacketLength(); - truePacketsSent++; - nodeData->resetVoxelPacket(); + + handlePacketSend(nodeList, node, nodeData, trueBytesSent, truePacketsSent); + } else { if (::debugVoxelSending) { printf("wantColor=%s --- FIXING HEADER! nodeData->getCurrentPacketIsColor()=%s\n", @@ -209,11 +244,6 @@ void deepestLevelVoxelDistributor(NodeList* nodeList, if (::displayVoxelStats) { nodeData->stats.printDebugDetails(); } - - // Send the stats message to the client - unsigned char statsMessage[MAX_PACKET_SIZE]; - int statsMessageLength = nodeData->stats.packIntoMessage(statsMessage, sizeof(statsMessage)); - nodeList->getNodeSocket()->send(node->getActiveSocket(), statsMessage, statsMessageLength); // This is the start of "resending" the scene. nodeData->nodeBag.insert(serverTree.rootNode); @@ -271,22 +301,14 @@ void deepestLevelVoxelDistributor(NodeList* nodeList, if (nodeData->getAvailable() >= bytesWritten) { nodeData->writeToPacket(&tempOutputBuffer[0], bytesWritten); } else { - nodeList->getNodeSocket()->send(node->getActiveSocket(), - nodeData->getPacket(), nodeData->getPacketLength()); - nodeData->stats.packetSent(nodeData->getPacketLength()); - trueBytesSent += nodeData->getPacketLength(); - truePacketsSent++; + handlePacketSend(nodeList, node, nodeData, trueBytesSent, truePacketsSent); packetsSentThisInterval++; nodeData->resetVoxelPacket(); nodeData->writeToPacket(&tempOutputBuffer[0], bytesWritten); } } else { if (nodeData->isPacketWaiting()) { - nodeList->getNodeSocket()->send(node->getActiveSocket(), - nodeData->getPacket(), nodeData->getPacketLength()); - nodeData->stats.packetSent(nodeData->getPacketLength()); - trueBytesSent += nodeData->getPacketLength(); - truePacketsSent++; + handlePacketSend(nodeList, node, nodeData, trueBytesSent, truePacketsSent); nodeData->resetVoxelPacket(); } packetsSentThisInterval = PACKETS_PER_CLIENT_PER_INTERVAL; // done for now, no nodes left