bool JurisdictionListener::queueJurisdictionRequest() {
    static unsigned char buffer[MAX_PACKET_SIZE];
    unsigned char* bufferOut = &buffer[0];
    ssize_t sizeOut = populateTypeAndVersion(bufferOut, PACKET_TYPE_VOXEL_JURISDICTION_REQUEST);
    int nodeCount = 0;

    NodeList* nodeList = NodeList::getInstance();
    for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {

        // only send to the NodeTypes that are interested in our jurisdiction details
        const int numNodeTypes = 1; 
        const NODE_TYPE nodeTypes[numNodeTypes] = { NODE_TYPE_VOXEL_SERVER };
        if (node->getActiveSocket() != NULL && memchr(nodeTypes, node->getType(), numNodeTypes)) {
            sockaddr* nodeAddress = node->getActiveSocket();
            PacketSender::queuePacketForSending(*nodeAddress, bufferOut, sizeOut);
            nodeCount++;
        }
    }

    // set our packets per second to be the number of nodes
    setPacketsPerSecond(nodeCount);
    
    // keep going if still running
    return isStillRunning();
}
Exemple #2
0
Node* NodeList::nodeWithAddress(sockaddr *senderAddress) {
    for(NodeList::iterator node = begin(); node != end(); node++) {
        if (node->getActiveSocket() && socketMatch(node->getActiveSocket(), senderAddress)) {
            return &(*node);
        }
    }
    
    return NULL;
}
Exemple #3
0
unsigned NodeList::broadcastToNodes(unsigned char* broadcastData, size_t dataBytes, const char* nodeTypes, int numNodeTypes) {
    unsigned n = 0;
    for(NodeList::iterator node = begin(); node != end(); node++) {
        // only send to the NodeTypes we are asked to send to.
        if (node->getActiveSocket() != NULL && memchr(nodeTypes, node->getType(), numNodeTypes)) {
            // we know which socket is good for this node, send there
            _nodeSocket.send(node->getActiveSocket(), broadcastData, dataBytes);
            ++n;
        }
    }
    return n;
}
bool JurisdictionListener::queueJurisdictionRequest() {
    //qDebug() << "JurisdictionListener::queueJurisdictionRequest()\n";

    static unsigned char buffer[MAX_PACKET_SIZE];
    unsigned char* bufferOut = &buffer[0];
    ssize_t sizeOut = populateTypeAndVersion(bufferOut, PACKET_TYPE_JURISDICTION_REQUEST);
    int nodeCount = 0;

    NodeList* nodeList = NodeList::getInstance();
    for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
        if (nodeList->getNodeActiveSocketOrPing(&(*node)) &&
                node->getType() == getNodeType()) {
            const HifiSockAddr* nodeAddress = node->getActiveSocket();
            PacketSender::queuePacketForSending(*nodeAddress, bufferOut, sizeOut);
            nodeCount++;
        }
    }

    if (nodeCount > 0) {
        setPacketsPerSecond(nodeCount);
    } else {
        setPacketsPerSecond(NO_SERVER_CHECK_RATE);
    }

    // keep going if still running
    return isStillRunning();
}
void VoxelEditPacketSender::queuePacketToNodes(unsigned char* buffer, ssize_t length) {
    if (!_shouldSend) {
        return; // bail early
    }
    
    assert(voxelServersExist()); // we must have jurisdictions to be here!!

    int headerBytes = numBytesForPacketHeader(buffer) + sizeof(short) + sizeof(uint64_t);
    unsigned char* octCode = buffer + headerBytes; // skip the packet header to get to the octcode
    
    // We want to filter out edit messages for voxel servers based on the server's Jurisdiction
    // But we can't really do that with a packed message, since each edit message could be destined 
    // for a different voxel server... So we need to actually manage multiple queued packets... one
    // for each voxel server
    NodeList* nodeList = NodeList::getInstance();
    for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
        // only send to the NodeTypes that are NODE_TYPE_VOXEL_SERVER
        if (node->getActiveSocket() != NULL && node->getType() == NODE_TYPE_VOXEL_SERVER) {
            QUuid nodeUUID = node->getUUID();
            bool isMyJurisdiction = true;
            // we need to get the jurisdiction for this 
            // here we need to get the "pending packet" for this server
            const JurisdictionMap& map = (*_voxelServerJurisdictions)[nodeUUID];
            isMyJurisdiction = (map.isMyJurisdiction(octCode, CHECK_NODE_ONLY) == JurisdictionMap::WITHIN);
            if (isMyJurisdiction) {
                queuePacketToNode(nodeUUID, buffer, length);
            }
        }
    }
}
Exemple #6
0
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.isReadyToSend()) {
        // 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();
}
Exemple #7
0
// NOTE: some additional optimizations to consider.
//    1) use the view frustum to cull those avatars that are out of view. Since avatar data doesn't need to be present
//       if the avatar is not in view or in the keyhole.
//    2) after culling for view frustum, sort order the avatars by distance, send the closest ones first.
//    3) if we need to rate limit the amount of data we send, we can use a distance weighted "semi-random" function to 
//       determine which avatars are included in the packet stream
//    4) we should optimize the avatar data format to be more compact (100 bytes is pretty wasteful).
void broadcastAvatarData(NodeList* nodeList, sockaddr* nodeAddress) {
    static unsigned char broadcastPacketBuffer[MAX_PACKET_SIZE];
    static unsigned char avatarDataBuffer[MAX_PACKET_SIZE];
    unsigned char* broadcastPacket = (unsigned char*)&broadcastPacketBuffer[0];
    int numHeaderBytes = populateTypeAndVersion(broadcastPacket, PACKET_TYPE_BULK_AVATAR_DATA);
    unsigned char* currentBufferPosition = broadcastPacket + numHeaderBytes;
    int packetLength = currentBufferPosition - broadcastPacket;
    int packetsSent = 0;

    // send back a packet with other active node data to this node
    for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
        if (node->getLinkedData() && !socketMatch(nodeAddress, node->getActiveSocket())) {
            unsigned char* avatarDataEndpoint = addNodeToBroadcastPacket((unsigned char*)&avatarDataBuffer[0], &*node);
            int avatarDataLength = avatarDataEndpoint - (unsigned char*)&avatarDataBuffer;

            if (avatarDataLength + packetLength <= MAX_PACKET_SIZE) {
                memcpy(currentBufferPosition, &avatarDataBuffer[0], avatarDataLength);
                packetLength += avatarDataLength;
                currentBufferPosition += avatarDataLength;
            } else {
                packetsSent++;
                //printf("packetsSent=%d packetLength=%d\n", packetsSent, packetLength);
                nodeList->getNodeSocket()->send(nodeAddress, broadcastPacket, currentBufferPosition - broadcastPacket);
                
                // reset the packet
                currentBufferPosition = broadcastPacket + numHeaderBytes;
                packetLength = currentBufferPosition - broadcastPacket;
                
                // copy the avatar that didn't fit into the next packet
                memcpy(currentBufferPosition, &avatarDataBuffer[0], avatarDataLength);
                packetLength += avatarDataLength;
                currentBufferPosition += avatarDataLength;
            }
        }
    }
    packetsSent++;
    //printf("packetsSent=%d packetLength=%d\n", packetsSent, packetLength);
    nodeList->getNodeSocket()->send(nodeAddress, broadcastPacket, currentBufferPosition - broadcastPacket);
}
// This method is called when the edit packet layer has determined that it has a fully formed packet destined for
// a known nodeID. However, we also want to handle the case where the 
void VoxelEditPacketSender::queuePacketToNode(const QUuid& nodeUUID, unsigned char* buffer, ssize_t length) {
    NodeList* nodeList = NodeList::getInstance();
    for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
        // only send to the NodeTypes that are NODE_TYPE_VOXEL_SERVER
        if (node->getType() == NODE_TYPE_VOXEL_SERVER &&
            ((node->getUUID() == nodeUUID) || (nodeUUID.isNull()))) {
            if (nodeList->getNodeActiveSocketOrPing(&(*node))) {
                sockaddr* nodeAddress = node->getActiveSocket();
                queuePacketForSending(*nodeAddress, buffer, length);
                
                // debugging output...
                bool wantDebugging = false;
                if (wantDebugging) {
                    int numBytesPacketHeader = numBytesForPacketHeader(buffer);
                    unsigned short int sequence = (*((unsigned short int*)(buffer + numBytesPacketHeader)));
                    uint64_t createdAt = (*((uint64_t*)(buffer + numBytesPacketHeader + sizeof(sequence))));
                    uint64_t queuedAt = usecTimestampNow();
                    uint64_t transitTime = queuedAt - createdAt;

                    const char* messageName;
                    switch (buffer[0]) {
                        case PACKET_TYPE_SET_VOXEL: 
                            messageName = "PACKET_TYPE_SET_VOXEL"; 
                            break;
                        case PACKET_TYPE_SET_VOXEL_DESTRUCTIVE: 
                            messageName = "PACKET_TYPE_SET_VOXEL_DESTRUCTIVE"; 
                            break;
                        case PACKET_TYPE_ERASE_VOXEL: 
                            messageName = "PACKET_TYPE_ERASE_VOXEL"; 
                            break;
                    }
                    printf("VoxelEditPacketSender::queuePacketToNode() queued %s - command to node bytes=%ld sequence=%d transitTimeSoFar=%llu usecs\n",
                        messageName, length, sequence, transitTime);
                }                
            }
        }
    }
}
Exemple #9
0
int main(int argc, const char* argv[]) {

    NodeList* nodeList = NodeList::createInstance(NODE_TYPE_AVATAR_MIXER, AVATAR_LISTEN_PORT);
    setvbuf(stdout, NULL, _IOLBF, 0);
    
    // Handle Local Domain testing with the --local command line
    const char* local = "--local";
    if (cmdOptionExists(argc, argv, local)) {
        printf("Local Domain MODE!\n");
        nodeList->setDomainIPToLocalhost();
    }
    
    nodeList->linkedDataCreateCallback = attachAvatarDataToNode;
    
    nodeList->startSilentNodeRemovalThread();
    
    sockaddr* nodeAddress = new sockaddr;
    ssize_t receivedBytes = 0;
    
    unsigned char* packetData = new unsigned char[MAX_PACKET_SIZE];
    
    
    uint16_t nodeID = 0;
    Node* avatarNode = NULL;
    
    timeval lastDomainServerCheckIn = {};
    // we only need to hear back about avatar nodes from the DS
    NodeList::getInstance()->setNodeTypesOfInterest(&NODE_TYPE_AGENT, 1);
    
    while (true) {
        
        // send a check in packet to the domain server if DOMAIN_SERVER_CHECK_IN_USECS has elapsed
        if (usecTimestampNow() - usecTimestamp(&lastDomainServerCheckIn) >= DOMAIN_SERVER_CHECK_IN_USECS) {
            gettimeofday(&lastDomainServerCheckIn, NULL);
            NodeList::getInstance()->sendDomainServerCheckIn();
        }
        
        if (nodeList->getNodeSocket()->receive(nodeAddress, packetData, &receivedBytes) &&
            packetVersionMatch(packetData)) {
            switch (packetData[0]) {
                case PACKET_TYPE_HEAD_DATA:
                    // grab the node ID from the packet
                    unpackNodeId(packetData + numBytesForPacketHeader(packetData), &nodeID);
                    
                    // add or update the node in our list
                    avatarNode = nodeList->addOrUpdateNode(nodeAddress, nodeAddress, NODE_TYPE_AGENT, nodeID);
                    
                    // parse positional data from an node
                    nodeList->updateNodeWithData(avatarNode, packetData, receivedBytes);
                case PACKET_TYPE_INJECT_AUDIO:
                    broadcastAvatarData(nodeList, nodeAddress);
                    break;
                case PACKET_TYPE_AVATAR_VOXEL_URL:
                case PACKET_TYPE_AVATAR_FACE_VIDEO:
                    // grab the node ID from the packet
                    unpackNodeId(packetData + numBytesForPacketHeader(packetData), &nodeID);
                    
                    // let everyone else know about the update
                    for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
                        if (node->getActiveSocket() && node->getNodeID() != nodeID) {
                            nodeList->getNodeSocket()->send(node->getActiveSocket(), packetData, receivedBytes);
                        }
                    }
                    break;
                case PACKET_TYPE_DOMAIN:
                    // ignore the DS packet, for now nodes are added only when they communicate directly with us
                    break;
                default:
                    // hand this off to the NodeList
                    nodeList->processNodeData(nodeAddress, packetData, receivedBytes);
                    break;
            }
        }
    }
    
    nodeList->stopSilentNodeRemovalThread();
    
    return 0;
}
// NOTE: codeColorBuffer - is JUST the octcode/color and does not contain the packet header!
void VoxelEditPacketSender::queueVoxelEditMessage(PACKET_TYPE type, unsigned char* codeColorBuffer, ssize_t length) {
    if (!_shouldSend) {
        return; // bail early
    }
    
    // If we don't have voxel jurisdictions, then we will simply queue up all of these packets and wait till we have
    // jurisdictions for processing
    if (!voxelServersExist()) {
        if (_maxPendingMessages > 0) {
            EditPacketBuffer* packet = new EditPacketBuffer(type, codeColorBuffer, length);
            _preServerPackets.push_back(packet);

            // if we've saved MORE than out max, then clear out the oldest packet...
            int allPendingMessages = _preServerSingleMessagePackets.size() + _preServerPackets.size();
            if (allPendingMessages > _maxPendingMessages) {
                EditPacketBuffer* packet = _preServerPackets.front();
                delete packet;
                _preServerPackets.erase(_preServerPackets.begin());
            }
        }
        return; // bail early
    }
    
    // We want to filter out edit messages for voxel servers based on the server's Jurisdiction
    // But we can't really do that with a packed message, since each edit message could be destined 
    // for a different voxel server... So we need to actually manage multiple queued packets... one
    // for each voxel server
    NodeList* nodeList = NodeList::getInstance();
    for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
        // only send to the NodeTypes that are NODE_TYPE_VOXEL_SERVER
        if (node->getActiveSocket() != NULL && node->getType() == NODE_TYPE_VOXEL_SERVER) {
            QUuid nodeUUID = node->getUUID();
            bool isMyJurisdiction = true;

            if (_voxelServerJurisdictions) {
                // we need to get the jurisdiction for this 
                // here we need to get the "pending packet" for this server
                if ((*_voxelServerJurisdictions).find(nodeUUID) != (*_voxelServerJurisdictions).end()) {
                    const JurisdictionMap& map = (*_voxelServerJurisdictions)[nodeUUID];
                    isMyJurisdiction = (map.isMyJurisdiction(codeColorBuffer, CHECK_NODE_ONLY) == JurisdictionMap::WITHIN);
                } else {
                    isMyJurisdiction = false;
                }
            }
            if (isMyJurisdiction) {
                EditPacketBuffer& packetBuffer = _pendingEditPackets[nodeUUID];
                packetBuffer._nodeUUID = nodeUUID;
            
                // If we're switching type, then we send the last one and start over
                if ((type != packetBuffer._currentType && packetBuffer._currentSize > 0) || 
                    (packetBuffer._currentSize + length >= _maxPacketSize)) {
                    releaseQueuedPacket(packetBuffer);
                    initializePacket(packetBuffer, type);
                }

                // If the buffer is empty and not correctly initialized for our type...
                if (type != packetBuffer._currentType && packetBuffer._currentSize == 0) {
                    initializePacket(packetBuffer, type);
                }

                memcpy(&packetBuffer._currentBuffer[packetBuffer._currentSize], codeColorBuffer, length);
                packetBuffer._currentSize += length;
            }
        }
    }
}
Exemple #11
0
// Version of voxel distributor that sends the deepest LOD level at once
void deepestLevelVoxelDistributor(NodeList* nodeList, 
                                  NodeList::iterator& node,
                                  VoxelNodeData* nodeData,
                                  bool viewFrustumChanged) {


    pthread_mutex_lock(&::treeLock);

    int truePacketsSent = 0;
    int trueBytesSent = 0;

    // FOR NOW... node tells us if it wants to receive only view frustum deltas
    bool wantDelta = viewFrustumChanged && nodeData->getWantDelta();

    // If our packet already has content in it, then we must use the color choice of the waiting packet.    
    // If we're starting a fresh packet, then... 
    //     If we're moving, and the client asked for low res, then we force monochrome, otherwise, use 
    //     the clients requested color state.
    bool wantColor = LOW_RES_MONO && nodeData->getWantLowResMoving() && viewFrustumChanged ? false : nodeData->getWantColor();

    // If we have a packet waiting, and our desired want color, doesn't match the current waiting packets color
    // then let's just send that waiting packet.    
    if (wantColor != nodeData->getCurrentPacketIsColor()) {
    
        if (nodeData->isPacketWaiting()) {
            if (::debugVoxelSending) {
                printf("wantColor=%s --- SENDING PARTIAL PACKET! nodeData->getCurrentPacketIsColor()=%s\n", 
                       debug::valueOf(wantColor), debug::valueOf(nodeData->getCurrentPacketIsColor()));
            }

            handlePacketSend(nodeList, node, nodeData, trueBytesSent, truePacketsSent);

        } else {
            if (::debugVoxelSending) {
                printf("wantColor=%s --- FIXING HEADER! nodeData->getCurrentPacketIsColor()=%s\n", 
                       debug::valueOf(wantColor), debug::valueOf(nodeData->getCurrentPacketIsColor()));
            }
            nodeData->resetVoxelPacket();
        }
    }
    
    if (::debugVoxelSending) {
        printf("wantColor=%s getCurrentPacketIsColor()=%s, viewFrustumChanged=%s, getWantLowResMoving()=%s\n", 
               debug::valueOf(wantColor), debug::valueOf(nodeData->getCurrentPacketIsColor()),
               debug::valueOf(viewFrustumChanged), debug::valueOf(nodeData->getWantLowResMoving()));
    }

    const ViewFrustum* lastViewFrustum =  wantDelta ? &nodeData->getLastKnownViewFrustum() : NULL;

    if (::debugVoxelSending) {
        printf("deepestLevelVoxelDistributor() viewFrustumChanged=%s, nodeBag.isEmpty=%s, viewSent=%s\n",
                debug::valueOf(viewFrustumChanged), debug::valueOf(nodeData->nodeBag.isEmpty()), 
                debug::valueOf(nodeData->getViewSent())
            );
    }
    
    // If the current view frustum has changed OR we have nothing to send, then search against 
    // the current view frustum for things to send.
    if (viewFrustumChanged || nodeData->nodeBag.isEmpty()) {
        uint64_t now = usecTimestampNow();
        if (::debugVoxelSending) {
            printf("(viewFrustumChanged=%s || nodeData->nodeBag.isEmpty() =%s)...\n",
                   debug::valueOf(viewFrustumChanged), debug::valueOf(nodeData->nodeBag.isEmpty()));
            if (nodeData->getLastTimeBagEmpty() > 0) {
                float elapsedSceneSend = (now - nodeData->getLastTimeBagEmpty()) / 1000000.0f;
                if (viewFrustumChanged) {
                    printf("viewFrustumChanged resetting after elapsed time to send scene = %f seconds", elapsedSceneSend);
                } else {
                    printf("elapsed time to send scene = %f seconds", elapsedSceneSend);
                }
                printf(" [occlusionCulling:%s, wantDelta:%s, wantColor:%s ]\n", 
                       debug::valueOf(nodeData->getWantOcclusionCulling()), debug::valueOf(wantDelta), 
                       debug::valueOf(wantColor));
            }
        }
                
        // if our view has changed, we need to reset these things...
        if (viewFrustumChanged) {
            nodeData->nodeBag.deleteAll();
            nodeData->map.erase();
        } 
        
        if (!viewFrustumChanged && !nodeData->getWantDelta()) {
            // only set our last sent time if we weren't resetting due to frustum change
            uint64_t now = usecTimestampNow();
            nodeData->setLastTimeBagEmpty(now);
        }
        
        nodeData->stats.sceneCompleted();
        
        if (::displayVoxelStats) {
            nodeData->stats.printDebugDetails();
        }
        
        // This is the start of "resending" the scene.
        nodeData->nodeBag.insert(serverTree.rootNode);
        
        // start tracking our stats
        bool isFullScene = (!viewFrustumChanged || !nodeData->getWantDelta()) && nodeData->getViewFrustumJustStoppedChanging();
        nodeData->stats.sceneStarted(isFullScene, viewFrustumChanged, ::serverTree.rootNode);
    }

    // If we have something in our nodeBag, then turn them into packets and send them out...
    if (!nodeData->nodeBag.isEmpty()) {
        static unsigned char tempOutputBuffer[MAX_VOXEL_PACKET_SIZE - 1]; // save on allocs by making this static
        int bytesWritten = 0;
        int packetsSentThisInterval = 0;
        uint64_t start = usecTimestampNow();

        bool shouldSendEnvironments = shouldDo(ENVIRONMENT_SEND_INTERVAL_USECS, VOXEL_SEND_INTERVAL_USECS);
        while (packetsSentThisInterval < PACKETS_PER_CLIENT_PER_INTERVAL - (shouldSendEnvironments ? 1 : 0)) {        
            // Check to see if we're taking too long, and if so bail early...
            uint64_t now = usecTimestampNow();
            long elapsedUsec = (now - start);
            long elapsedUsecPerPacket = (truePacketsSent == 0) ? 0 : (elapsedUsec / truePacketsSent);
            long usecRemaining = (VOXEL_SEND_INTERVAL_USECS - elapsedUsec);
            
            if (elapsedUsecPerPacket + SENDING_TIME_TO_SPARE > usecRemaining) {
                if (::debugVoxelSending) {
                    printf("packetLoop() usecRemaining=%ld bailing early took %ld usecs to generate %d bytes in %d packets (%ld usec avg), %d nodes still to send\n",
                            usecRemaining, elapsedUsec, trueBytesSent, truePacketsSent, elapsedUsecPerPacket,
                            nodeData->nodeBag.count());
                }
                break;
            }            
            
            if (!nodeData->nodeBag.isEmpty()) {
                VoxelNode* subTree = nodeData->nodeBag.extract();
                bool wantOcclusionCulling = nodeData->getWantOcclusionCulling();
                CoverageMap* coverageMap = wantOcclusionCulling ? &nodeData->map : IGNORE_COVERAGE_MAP;
                int boundaryLevelAdjust = viewFrustumChanged && nodeData->getWantLowResMoving() 
                                          ? LOW_RES_MOVING_ADJUST : NO_BOUNDARY_ADJUST;

                bool isFullScene = (!viewFrustumChanged || !nodeData->getWantDelta()) && 
                                 nodeData->getViewFrustumJustStoppedChanging();
                
                EncodeBitstreamParams params(INT_MAX, &nodeData->getCurrentViewFrustum(), wantColor, 
                                             WANT_EXISTS_BITS, DONT_CHOP, wantDelta, lastViewFrustum,
                                             wantOcclusionCulling, coverageMap, boundaryLevelAdjust,
                                             nodeData->getLastTimeBagEmpty(),
                                             isFullScene, &nodeData->stats);
                      
                nodeData->stats.encodeStarted();
                bytesWritten = serverTree.encodeTreeBitstream(subTree, &tempOutputBuffer[0], MAX_VOXEL_PACKET_SIZE - 1,
                                                              nodeData->nodeBag, params);
                nodeData->stats.encodeStopped();

                if (nodeData->getAvailable() >= bytesWritten) {
                    nodeData->writeToPacket(&tempOutputBuffer[0], bytesWritten);
                } else {
                    handlePacketSend(nodeList, node, nodeData, trueBytesSent, truePacketsSent);
                    packetsSentThisInterval++;
                    nodeData->resetVoxelPacket();
                    nodeData->writeToPacket(&tempOutputBuffer[0], bytesWritten);
                }
            } else {
                if (nodeData->isPacketWaiting()) {
                    handlePacketSend(nodeList, node, nodeData, trueBytesSent, truePacketsSent);
                    nodeData->resetVoxelPacket();
                }
                packetsSentThisInterval = PACKETS_PER_CLIENT_PER_INTERVAL; // done for now, no nodes left
            }
        }
        // send the environment packet
        if (shouldSendEnvironments) {
            int numBytesPacketHeader = populateTypeAndVersion(tempOutputBuffer, PACKET_TYPE_ENVIRONMENT_DATA);
            int envPacketLength = numBytesPacketHeader;
            
            for (int i = 0; i < sizeof(environmentData) / sizeof(EnvironmentData); i++) {
                envPacketLength += environmentData[i].getBroadcastData(tempOutputBuffer + envPacketLength);
            }
            
            nodeList->getNodeSocket()->send(node->getActiveSocket(), tempOutputBuffer, envPacketLength);
            trueBytesSent += envPacketLength;
            truePacketsSent++;
        }
        
        uint64_t end = usecTimestampNow();
        int elapsedmsec = (end - start)/1000;
        if (elapsedmsec > 100) {
            if (elapsedmsec > 1000) {
                int elapsedsec = (end - start)/1000000;
                printf("WARNING! packetLoop() took %d seconds to generate %d bytes in %d packets %d nodes still to send\n",
                        elapsedsec, trueBytesSent, truePacketsSent, nodeData->nodeBag.count());
            } else {
                printf("WARNING! packetLoop() took %d milliseconds to generate %d bytes in %d packets, %d nodes still to send\n",
                        elapsedmsec, trueBytesSent, truePacketsSent, nodeData->nodeBag.count());
            }
        } else if (::debugVoxelSending) {
            printf("packetLoop() took %d milliseconds to generate %d bytes in %d packets, %d nodes still to send\n",
                    elapsedmsec, trueBytesSent, truePacketsSent, nodeData->nodeBag.count());
        }
        
        // if after sending packets we've emptied our bag, then we want to remember that we've sent all 
        // the voxels from the current view frustum
        if (nodeData->nodeBag.isEmpty()) {
            nodeData->updateLastKnownViewFrustum();
            nodeData->setViewSent(true);
            if (::debugVoxelSending) {
                nodeData->map.printStats();
            }
            nodeData->map.erase(); // It would be nice if we could save this, and only reset it when the view frustum changes
        }
        
    } // end if bag wasn't empty, and so we sent stuff...

    pthread_mutex_unlock(&::treeLock);
}
Exemple #12
0
void AvatarMixer::run() {
    // change the logging target name while AvatarMixer is running
    Logging::setTargetName(AVATAR_MIXER_LOGGING_NAME);
    
    NodeList* nodeList = NodeList::getInstance();
    nodeList->setOwnerType(NODE_TYPE_AVATAR_MIXER);
    
    nodeList->setNodeTypesOfInterest(&NODE_TYPE_AGENT, 1);
    
    nodeList->linkedDataCreateCallback = attachAvatarDataToNode;
    
    nodeList->startSilentNodeRemovalThread();
    
    sockaddr nodeAddress = {};
    ssize_t receivedBytes = 0;
    
    unsigned char packetData[MAX_PACKET_SIZE];
    
    QUuid nodeUUID;
    Node* avatarNode = NULL;
    
    timeval lastDomainServerCheckIn = {};
    
    while (true) {
        
        if (NodeList::getInstance()->getNumNoReplyDomainCheckIns() == MAX_SILENT_DOMAIN_SERVER_CHECK_INS) {
            break;
        }
        
        // send a check in packet to the domain server if DOMAIN_SERVER_CHECK_IN_USECS has elapsed
        if (usecTimestampNow() - usecTimestamp(&lastDomainServerCheckIn) >= DOMAIN_SERVER_CHECK_IN_USECS) {
            gettimeofday(&lastDomainServerCheckIn, NULL);
            NodeList::getInstance()->sendDomainServerCheckIn();
        }
        
        nodeList->possiblyPingInactiveNodes();
        
        if (nodeList->getNodeSocket()->receive(&nodeAddress, packetData, &receivedBytes) &&
            packetVersionMatch(packetData)) {
            switch (packetData[0]) {
                case PACKET_TYPE_HEAD_DATA:
                    nodeUUID = QUuid::fromRfc4122(QByteArray((char*) packetData + numBytesForPacketHeader(packetData),
                                                                   NUM_BYTES_RFC4122_UUID));
                    
                    // add or update the node in our list
                    avatarNode = nodeList->nodeWithUUID(nodeUUID);
                    
                    if (avatarNode) {
                        // parse positional data from an node
                        nodeList->updateNodeWithData(avatarNode, &nodeAddress, packetData, receivedBytes);
                    } else {
                        break;
                    }
                case PACKET_TYPE_INJECT_AUDIO:
                    broadcastAvatarData(nodeList, nodeUUID, &nodeAddress);
                    break;
                case PACKET_TYPE_AVATAR_URLS:
                case PACKET_TYPE_AVATAR_FACE_VIDEO:
                    nodeUUID = QUuid::fromRfc4122(QByteArray((char*) packetData + numBytesForPacketHeader(packetData),
                                                             NUM_BYTES_RFC4122_UUID));
                    // let everyone else know about the update
                    for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
                        if (node->getActiveSocket() && node->getUUID() != nodeUUID) {
                            nodeList->getNodeSocket()->send(node->getActiveSocket(), packetData, receivedBytes);
                        }
                    }
                    break;
                default:
                    // hand this off to the NodeList
                    nodeList->processNodeData(&nodeAddress, packetData, receivedBytes);
                    break;
            }
        }
    }
    
    nodeList->stopSilentNodeRemovalThread();
}
Exemple #13
0
void AvatarMixer::run() {
    // change the logging target name while AvatarMixer is running
    Logging::setTargetName(AVATAR_MIXER_LOGGING_NAME);
    
    NodeList* nodeList = NodeList::getInstance();
    nodeList->setOwnerType(NODE_TYPE_AVATAR_MIXER);
    
    nodeList->linkedDataCreateCallback = attachAvatarDataToNode;
    
    nodeList->startSilentNodeRemovalThread();
    
    sockaddr* nodeAddress = new sockaddr;
    ssize_t receivedBytes = 0;
    
    unsigned char* packetData = new unsigned char[MAX_PACKET_SIZE];
    
    uint16_t nodeID = 0;
    Node* avatarNode = NULL;
    
    timeval lastDomainServerCheckIn = {};
    // we only need to hear back about avatar nodes from the DS
    nodeList->setNodeTypesOfInterest(&NODE_TYPE_AGENT, 1);
    
    while (true) {
        
        if (NodeList::getInstance()->getNumNoReplyDomainCheckIns() == MAX_SILENT_DOMAIN_SERVER_CHECK_INS) {
            break;
        }
        
        // send a check in packet to the domain server if DOMAIN_SERVER_CHECK_IN_USECS has elapsed
        if (usecTimestampNow() - usecTimestamp(&lastDomainServerCheckIn) >= DOMAIN_SERVER_CHECK_IN_USECS) {
            gettimeofday(&lastDomainServerCheckIn, NULL);
            NodeList::getInstance()->sendDomainServerCheckIn();
        }
        
        if (nodeList->getNodeSocket()->receive(nodeAddress, packetData, &receivedBytes) &&
            packetVersionMatch(packetData)) {
            switch (packetData[0]) {
                case PACKET_TYPE_HEAD_DATA:
                    // grab the node ID from the packet
                    unpackNodeId(packetData + numBytesForPacketHeader(packetData), &nodeID);
                    
                    // add or update the node in our list
                    avatarNode = nodeList->addOrUpdateNode(nodeAddress, nodeAddress, NODE_TYPE_AGENT, nodeID);
                    
                    // parse positional data from an node
                    nodeList->updateNodeWithData(avatarNode, packetData, receivedBytes);
                case PACKET_TYPE_INJECT_AUDIO:
                    broadcastAvatarData(nodeList, nodeAddress);
                    break;
                case PACKET_TYPE_AVATAR_VOXEL_URL:
                case PACKET_TYPE_AVATAR_FACE_VIDEO:
                    // grab the node ID from the packet
                    unpackNodeId(packetData + numBytesForPacketHeader(packetData), &nodeID);
                    
                    // let everyone else know about the update
                    for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
                        if (node->getActiveSocket() && node->getNodeID() != nodeID) {
                            nodeList->getNodeSocket()->send(node->getActiveSocket(), packetData, receivedBytes);
                        }
                    }
                    break;
                default:
                    // hand this off to the NodeList
                    nodeList->processNodeData(nodeAddress, packetData, receivedBytes);
                    break;
            }
        }
    }
    
    nodeList->stopSilentNodeRemovalThread();
}