Пример #1
0
void AudioMixer::readPendingDatagram(const QByteArray& receivedPacket, const HifiSockAddr& senderSockAddr) {
    NodeList* nodeList = NodeList::getInstance();
    
    if (nodeList->packetVersionAndHashMatch(receivedPacket)) {
        // pull any new audio data from nodes off of the network stack
        PacketType mixerPacketType = packetTypeForPacket(receivedPacket);
        if (mixerPacketType == PacketTypeMicrophoneAudioNoEcho
            || mixerPacketType == PacketTypeMicrophoneAudioWithEcho
            || mixerPacketType == PacketTypeInjectAudio
            || mixerPacketType == PacketTypeSilentAudioFrame
            || mixerPacketType == PacketTypeAudioStreamStats) {
            
            nodeList->findNodeAndUpdateWithDataFromPacket(receivedPacket);
        } else if (mixerPacketType == PacketTypeMuteEnvironment) {
            QByteArray packet = receivedPacket;
            populatePacketHeader(packet, PacketTypeMuteEnvironment);
            
            foreach (const SharedNodePointer& node, nodeList->getNodeHash()) {
                if (node->getType() == NodeType::Agent && node->getActiveSocket() && node->getLinkedData() && node != nodeList->sendingNodeForPacket(receivedPacket)) {
                    nodeList->writeDatagram(packet, packet.size(), node);
                }
            }
            
        } else {
Пример #2
0
void Agent::readPendingDatagrams() {
    QByteArray receivedPacket;
    HifiSockAddr senderSockAddr;
    NodeList* nodeList = NodeList::getInstance();
    
    while (readAvailableDatagram(receivedPacket, senderSockAddr)) {
        if (nodeList->packetVersionAndHashMatch(receivedPacket)) {
            PacketType datagramPacketType = packetTypeForPacket(receivedPacket);
            
            if (datagramPacketType == PacketTypeJurisdiction) {
                int headerBytes = numBytesForPacketHeader(receivedPacket);
                
                SharedNodePointer matchedNode = nodeList->sendingNodeForPacket(receivedPacket);
                
                if (matchedNode) {
                    // PacketType_JURISDICTION, first byte is the node type...
                    switch (receivedPacket[headerBytes]) {
                        case NodeType::VoxelServer:
                            _scriptEngine.getVoxelsScriptingInterface()->getJurisdictionListener()->
                                                                queueReceivedPacket(matchedNode,receivedPacket);
                            break;
                        case NodeType::ParticleServer:
                            _scriptEngine.getParticlesScriptingInterface()->getJurisdictionListener()->
                                                                queueReceivedPacket(matchedNode, receivedPacket);
                            break;
                        case NodeType::ModelServer:
                            _scriptEngine.getModelsScriptingInterface()->getJurisdictionListener()->
                                                                queueReceivedPacket(matchedNode, receivedPacket);
                            break;
                    }
                }
                
            } else if (datagramPacketType == PacketTypeParticleAddResponse) {
                // this will keep creatorTokenIDs to IDs mapped correctly
                Particle::handleAddParticleResponse(receivedPacket);
                
                // also give our local particle tree a chance to remap any internal locally created particles
                _particleViewer.getTree()->handleAddParticleResponse(receivedPacket);

                // Make sure our Node and NodeList knows we've heard from this node.
                SharedNodePointer sourceNode = nodeList->sendingNodeForPacket(receivedPacket);
                sourceNode->setLastHeardMicrostamp(usecTimestampNow());

            } else if (datagramPacketType == PacketTypeModelAddResponse) {
                // this will keep creatorTokenIDs to IDs mapped correctly
                ModelItem::handleAddModelResponse(receivedPacket);
                
                // also give our local particle tree a chance to remap any internal locally created particles
                _modelViewer.getTree()->handleAddModelResponse(receivedPacket);

                // Make sure our Node and NodeList knows we've heard from this node.
                SharedNodePointer sourceNode = nodeList->sendingNodeForPacket(receivedPacket);
                sourceNode->setLastHeardMicrostamp(usecTimestampNow());

            } else if (datagramPacketType == PacketTypeParticleData
                        || datagramPacketType == PacketTypeParticleErase
                        || datagramPacketType == PacketTypeOctreeStats
                        || datagramPacketType == PacketTypeVoxelData
                        || datagramPacketType == PacketTypeModelData
                        || datagramPacketType == PacketTypeModelErase
            ) {
                // Make sure our Node and NodeList knows we've heard from this node.
                SharedNodePointer sourceNode = nodeList->sendingNodeForPacket(receivedPacket);
                sourceNode->setLastHeardMicrostamp(usecTimestampNow());

                QByteArray mutablePacket = receivedPacket;
                int messageLength = mutablePacket.size();

                if (datagramPacketType == PacketTypeOctreeStats) {

                    int statsMessageLength = OctreeHeadlessViewer::parseOctreeStats(mutablePacket, sourceNode);
                    if (messageLength > statsMessageLength) {
                        mutablePacket = mutablePacket.mid(statsMessageLength);
                        
                        // TODO: this needs to be fixed, the goal is to test the packet version for the piggyback, but
                        //       this is testing the version and hash of the original packet
                        //       need to use numBytesArithmeticCodingFromBuffer()...
                        if (!NodeList::getInstance()->packetVersionAndHashMatch(receivedPacket)) {
                            return; // bail since piggyback data doesn't match our versioning
                        }
                    } else {
                        return; // bail since no piggyback data
                    }

                    datagramPacketType = packetTypeForPacket(mutablePacket);
                } // fall through to piggyback message

                if (datagramPacketType == PacketTypeParticleData || datagramPacketType == PacketTypeParticleErase) {
                    _particleViewer.processDatagram(mutablePacket, sourceNode);
                }

                if (datagramPacketType == PacketTypeModelData || datagramPacketType == PacketTypeModelErase) {
                    _modelViewer.processDatagram(mutablePacket, sourceNode);
                }
                
                if (datagramPacketType == PacketTypeVoxelData) {
                    _voxelViewer.processDatagram(mutablePacket, sourceNode);
                }

            } else if (datagramPacketType == PacketTypeMixedAudio || datagramPacketType == PacketTypeSilentAudioFrame) {

                _receivedAudioStream.parseData(receivedPacket);

                _lastReceivedAudioLoudness = _receivedAudioStream.getNextOutputFrameLoudness();

                _receivedAudioStream.clearBuffer();
                
                // let this continue through to the NodeList so it updates last heard timestamp
                // for the sending audio mixer
                NodeList::getInstance()->processNodeData(senderSockAddr, receivedPacket);
            } else if (datagramPacketType == PacketTypeBulkAvatarData
                       || datagramPacketType == PacketTypeAvatarIdentity
                       || datagramPacketType == PacketTypeAvatarBillboard
                       || datagramPacketType == PacketTypeKillAvatar) {
                // let the avatar hash map process it
                _avatarHashMap.processAvatarMixerDatagram(receivedPacket, nodeList->sendingNodeForPacket(receivedPacket));
                
                // let this continue through to the NodeList so it updates last heard timestamp
                // for the sending avatar-mixer
                NodeList::getInstance()->processNodeData(senderSockAddr, receivedPacket);
            } else {
                NodeList::getInstance()->processNodeData(senderSockAddr, receivedPacket);
            }
        }
    }
}
Пример #3
0
void DatagramProcessor::processDatagrams() {
    PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
                            "DatagramProcessor::processDatagrams()");
    
    HifiSockAddr senderSockAddr;
    
    static QByteArray incomingPacket;
    
    Application* application = Application::getInstance();
    NodeList* nodeList = NodeList::getInstance();
    
    while (NodeList::getInstance()->getNodeSocket().hasPendingDatagrams()) {
        incomingPacket.resize(nodeList->getNodeSocket().pendingDatagramSize());
        nodeList->getNodeSocket().readDatagram(incomingPacket.data(), incomingPacket.size(),
                                               senderSockAddr.getAddressPointer(), senderSockAddr.getPortPointer());
        
        _packetCount++;
        _byteCount += incomingPacket.size();
        
        if (nodeList->packetVersionAndHashMatch(incomingPacket)) {
            // only process this packet if we have a match on the packet version
            switch (packetTypeForPacket(incomingPacket)) {
                case PacketTypeTransmitterData:
                    //  V2 = IOS transmitter app
                    application->getAvatar()->getTransmitter().processIncomingData(reinterpret_cast<unsigned char*>(incomingPacket.data()),
                                                                    incomingPacket.size());
                    
                    break;
                case PacketTypeMixedAudio:
                    QMetaObject::invokeMethod(&application->_audio, "addReceivedAudioToBuffer", Qt::QueuedConnection,
                                              Q_ARG(QByteArray, incomingPacket));
                    break;
                    
                case PacketTypeParticleAddResponse:
                    // this will keep creatorTokenIDs to IDs mapped correctly
                    Particle::handleAddParticleResponse(incomingPacket);
                    application->getParticles()->getTree()->handleAddParticleResponse(incomingPacket);
                    break;
                    
                case PacketTypeParticleData:
                case PacketTypeParticleErase:
                case PacketTypeVoxelData:
                case PacketTypeVoxelErase:
                case PacketTypeOctreeStats:
                case PacketTypeEnvironmentData: {
                    PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
                                            "Application::networkReceive()... _voxelProcessor.queueReceivedPacket()");
                    
                    bool wantExtraDebugging = application->getLogger()->extraDebugging();
                    if (wantExtraDebugging && packetTypeForPacket(incomingPacket) == PacketTypeVoxelData) {
                        int numBytesPacketHeader = numBytesForPacketHeader(incomingPacket);
                        unsigned char* dataAt = reinterpret_cast<unsigned char*>(incomingPacket.data()) + numBytesPacketHeader;
                        dataAt += sizeof(OCTREE_PACKET_FLAGS);
                        OCTREE_PACKET_SEQUENCE sequence = (*(OCTREE_PACKET_SEQUENCE*)dataAt);
                        dataAt += sizeof(OCTREE_PACKET_SEQUENCE);
                        OCTREE_PACKET_SENT_TIME sentAt = (*(OCTREE_PACKET_SENT_TIME*)dataAt);
                        dataAt += sizeof(OCTREE_PACKET_SENT_TIME);
                        OCTREE_PACKET_SENT_TIME arrivedAt = usecTimestampNow();
                        int flightTime = arrivedAt - sentAt;
                        
                        printf("got PacketType_VOXEL_DATA, sequence:%d flightTime:%d\n", sequence, flightTime);
                    }
                    
                    SharedNodePointer matchedNode = NodeList::getInstance()->sendingNodeForPacket(incomingPacket);
                    
                    if (matchedNode) {
                        // add this packet to our list of voxel packets and process them on the voxel processing
                        application->_voxelProcessor.queueReceivedPacket(matchedNode, incomingPacket);
                    }
                    
                    break;
                }
                case PacketTypeMetavoxelData:
                    nodeList->findNodeAndUpdateWithDataFromPacket(incomingPacket);
                    break;
                case PacketTypeBulkAvatarData:
                case PacketTypeKillAvatar:
                case PacketTypeAvatarIdentity:
                case PacketTypeAvatarBillboard: {
                    // update having heard from the avatar-mixer and record the bytes received
                    SharedNodePointer avatarMixer = nodeList->sendingNodeForPacket(incomingPacket);
                    
                    if (avatarMixer) {
                        avatarMixer->setLastHeardMicrostamp(usecTimestampNow());
                        avatarMixer->recordBytesReceived(incomingPacket.size());
                        
                        QMetaObject::invokeMethod(&application->getAvatarManager(), "processAvatarMixerDatagram",
                                                  Q_ARG(const QByteArray&, incomingPacket),
                                                  Q_ARG(const QWeakPointer<Node>&, avatarMixer));
                    }
                    
                    application->_bandwidthMeter.inputStream(BandwidthMeter::AVATARS).updateValue(incomingPacket.size());
                    break;
                }
                case PacketTypeDataServerGet:
                case PacketTypeDataServerPut:
                case PacketTypeDataServerSend:
                case PacketTypeDataServerConfirm:
                    DataServerClient::processMessageFromDataServer(incomingPacket);
                    break;
                default:
                    nodeList->processNodeData(senderSockAddr, incomingPacket);
                    break;
            }
        }
    }
}
Пример #4
0
void DatagramProcessor::processDatagrams() {
    PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
                            "DatagramProcessor::processDatagrams()");
    
    HifiSockAddr senderSockAddr;
    
    static QByteArray incomingPacket;
    
    Application* application = Application::getInstance();
    NodeList* nodeList = NodeList::getInstance();
    
    while (NodeList::getInstance()->getNodeSocket().hasPendingDatagrams()) {
        incomingPacket.resize(nodeList->getNodeSocket().pendingDatagramSize());
        nodeList->getNodeSocket().readDatagram(incomingPacket.data(), incomingPacket.size(),
                                               senderSockAddr.getAddressPointer(), senderSockAddr.getPortPointer());
        
        _packetCount++;
        _byteCount += incomingPacket.size();
        
        if (nodeList->packetVersionAndHashMatch(incomingPacket)) {
            
            PacketType incomingType = packetTypeForPacket(incomingPacket);
            // only process this packet if we have a match on the packet version
            switch (incomingType) {
                case PacketTypeAudioEnvironment:
                case PacketTypeAudioStreamStats:
                case PacketTypeMixedAudio:
                case PacketTypeSilentAudioFrame: {
                    if (incomingType == PacketTypeAudioStreamStats) {
                        QMetaObject::invokeMethod(&application->_audio, "parseAudioStreamStatsPacket", Qt::QueuedConnection,
                                                  Q_ARG(QByteArray, incomingPacket));
                    } else if (incomingType == PacketTypeAudioEnvironment) {
                        QMetaObject::invokeMethod(&application->_audio, "parseAudioEnvironmentData", Qt::QueuedConnection,
                                                  Q_ARG(QByteArray, incomingPacket));
                    } else {
                        QMetaObject::invokeMethod(&application->_audio, "addReceivedAudioToStream", Qt::QueuedConnection,
                                                  Q_ARG(QByteArray, incomingPacket));
                    }
                    
                    // update having heard from the audio-mixer and record the bytes received
                    SharedNodePointer audioMixer = nodeList->sendingNodeForPacket(incomingPacket);
                    
                    if (audioMixer) {
                        audioMixer->setLastHeardMicrostamp(usecTimestampNow());
                        audioMixer->recordBytesReceived(incomingPacket.size());
                    }
                    
                    break;
                }
                case PacketTypeEntityAddResponse:
                    // this will keep creatorTokenIDs to IDs mapped correctly
                    EntityItemID::handleAddEntityResponse(incomingPacket);
                    application->getEntities()->getTree()->handleAddEntityResponse(incomingPacket);
                    break;
                case PacketTypeEntityData:
                case PacketTypeEntityErase:
                case PacketTypeVoxelData:
                case PacketTypeVoxelErase:
                case PacketTypeOctreeStats:
                case PacketTypeEnvironmentData: {
                    PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
                                            "Application::networkReceive()... _octreeProcessor.queueReceivedPacket()");
                    bool wantExtraDebugging = application->getLogger()->extraDebugging();
                    if (wantExtraDebugging && packetTypeForPacket(incomingPacket) == PacketTypeVoxelData) {
                        int numBytesPacketHeader = numBytesForPacketHeader(incomingPacket);
                        unsigned char* dataAt = reinterpret_cast<unsigned char*>(incomingPacket.data()) + numBytesPacketHeader;
                        dataAt += sizeof(OCTREE_PACKET_FLAGS);
                        OCTREE_PACKET_SEQUENCE sequence = (*(OCTREE_PACKET_SEQUENCE*)dataAt);
                        dataAt += sizeof(OCTREE_PACKET_SEQUENCE);
                        OCTREE_PACKET_SENT_TIME sentAt = (*(OCTREE_PACKET_SENT_TIME*)dataAt);
                        dataAt += sizeof(OCTREE_PACKET_SENT_TIME);
                        OCTREE_PACKET_SENT_TIME arrivedAt = usecTimestampNow();
                        int flightTime = arrivedAt - sentAt;
                        
                        qDebug("got an Octree data or erase message, sequence:%d flightTime:%d", sequence, flightTime);
                    }
                    
                    SharedNodePointer matchedNode = NodeList::getInstance()->sendingNodeForPacket(incomingPacket);
                    
                    if (matchedNode) {
                        // add this packet to our list of voxel packets and process them on the voxel processing
                        application->_octreeProcessor.queueReceivedPacket(matchedNode, incomingPacket);
                    }
                    
                    break;
                }
                case PacketTypeMetavoxelData:
                    nodeList->findNodeAndUpdateWithDataFromPacket(incomingPacket);
                    break;
                case PacketTypeBulkAvatarData:
                case PacketTypeKillAvatar:
                case PacketTypeAvatarIdentity:
                case PacketTypeAvatarBillboard: {
                    // update having heard from the avatar-mixer and record the bytes received
                    SharedNodePointer avatarMixer = nodeList->sendingNodeForPacket(incomingPacket);
                    
                    if (avatarMixer) {
                        avatarMixer->setLastHeardMicrostamp(usecTimestampNow());
                        avatarMixer->recordBytesReceived(incomingPacket.size());
                        
                        QMetaObject::invokeMethod(&application->getAvatarManager(), "processAvatarMixerDatagram",
                                                  Q_ARG(const QByteArray&, incomingPacket),
                                                  Q_ARG(const QWeakPointer<Node>&, avatarMixer));
                    }
                    
                    application->_bandwidthMeter.inputStream(BandwidthMeter::AVATARS).updateValue(incomingPacket.size());
                    break;
                }
                case PacketTypeDomainConnectionDenied: {
                    // output to the log so the user knows they got a denied connection request
                    // and check and signal for an access token so that we can make sure they are logged in
                    qDebug() << "The domain-server denied a connection request.";
                    qDebug() << "You may need to re-log to generate a keypair so you can provide a username signature.";
                    AccountManager::getInstance().checkAndSignalForAccessToken();
                    break;
                }
                case PacketTypeNoisyMute:
                case PacketTypeMuteEnvironment: {
                    bool mute = !Application::getInstance()->getAudio()->getMuted();
                    
                    if (incomingType == PacketTypeMuteEnvironment) {
                        glm::vec3 position;
                        float radius, distance;
                        
                        int headerSize = numBytesForPacketHeaderGivenPacketType(PacketTypeMuteEnvironment);
                        memcpy(&position, incomingPacket.constData() + headerSize, sizeof(glm::vec3));
                        memcpy(&radius, incomingPacket.constData() + headerSize + sizeof(glm::vec3), sizeof(float));
                        distance = glm::distance(Application::getInstance()->getAvatar()->getPosition(), position);
                        
                        mute = mute && (distance < radius);
                    }
                    
                    if (mute) {
                        Application::getInstance()->getAudio()->toggleMute();
                        if (incomingType == PacketTypeMuteEnvironment) {
                            AudioScriptingInterface::getInstance().environmentMuted();
                        } else {
                            AudioScriptingInterface::getInstance().mutedByMixer();
                        }
                    }
                    break;
                }
                case PacketTypeVoxelEditNack:
                    if (!Menu::getInstance()->isOptionChecked(MenuOption::DisableNackPackets)) {
                        application->_voxelEditSender.processNackPacket(incomingPacket);
                    }
                    break;
                case PacketTypeEntityEditNack:
                    if (!Menu::getInstance()->isOptionChecked(MenuOption::DisableNackPackets)) {
                        application->_entityEditSender.processNackPacket(incomingPacket);
                    }
                    break;
                default:
                    nodeList->processNodeData(senderSockAddr, incomingPacket);
                    break;
            }
        }
    }
Пример #5
0
void DatagramProcessor::processDatagrams() {
    PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
                            "DatagramProcessor::processDatagrams()");
    
    HifiSockAddr senderSockAddr;
    
    static QByteArray incomingPacket;
    
    Application* application = Application::getInstance();
    NodeList* nodeList = NodeList::getInstance();
    
    while (NodeList::getInstance()->getNodeSocket().hasPendingDatagrams()) {
        incomingPacket.resize(nodeList->getNodeSocket().pendingDatagramSize());
        nodeList->getNodeSocket().readDatagram(incomingPacket.data(), incomingPacket.size(),
                                               senderSockAddr.getAddressPointer(), senderSockAddr.getPortPointer());
        
        _packetCount++;
        _byteCount += incomingPacket.size();
        
        if (nodeList->packetVersionAndHashMatch(incomingPacket)) {
            // only process this packet if we have a match on the packet version
            switch (packetTypeForPacket(incomingPacket)) {
                case PacketTypeMixedAudio:
                case PacketTypeSilentAudioFrame:
                    QMetaObject::invokeMethod(&application->_audio, "addReceivedAudioToStream", Qt::QueuedConnection,
                                              Q_ARG(QByteArray, incomingPacket));
                    break;
                case PacketTypeAudioStreamStats:
                    QMetaObject::invokeMethod(&application->_audio, "parseAudioStreamStatsPacket", Qt::QueuedConnection,
                        Q_ARG(QByteArray, incomingPacket));
                    break;
                case PacketTypeParticleAddResponse:
                    // this will keep creatorTokenIDs to IDs mapped correctly
                    Particle::handleAddParticleResponse(incomingPacket);
                    application->getParticles()->getTree()->handleAddParticleResponse(incomingPacket);
                    break;
                case PacketTypeModelAddResponse:
                    // this will keep creatorTokenIDs to IDs mapped correctly
                    ModelItem::handleAddModelResponse(incomingPacket);
                    application->getModels()->getTree()->handleAddModelResponse(incomingPacket);
                    break;
                case PacketTypeParticleData:
                case PacketTypeParticleErase:
                case PacketTypeModelData:
                case PacketTypeModelErase:
                case PacketTypeVoxelData:
                case PacketTypeVoxelErase:
                case PacketTypeOctreeStats:
                case PacketTypeEnvironmentData: {
                    PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
                                            "Application::networkReceive()... _octreeProcessor.queueReceivedPacket()");
                    
                    bool wantExtraDebugging = application->getLogger()->extraDebugging();
                    if (wantExtraDebugging && packetTypeForPacket(incomingPacket) == PacketTypeVoxelData) {
                        int numBytesPacketHeader = numBytesForPacketHeader(incomingPacket);
                        unsigned char* dataAt = reinterpret_cast<unsigned char*>(incomingPacket.data()) + numBytesPacketHeader;
                        dataAt += sizeof(OCTREE_PACKET_FLAGS);
                        OCTREE_PACKET_SEQUENCE sequence = (*(OCTREE_PACKET_SEQUENCE*)dataAt);
                        dataAt += sizeof(OCTREE_PACKET_SEQUENCE);
                        OCTREE_PACKET_SENT_TIME sentAt = (*(OCTREE_PACKET_SENT_TIME*)dataAt);
                        dataAt += sizeof(OCTREE_PACKET_SENT_TIME);
                        OCTREE_PACKET_SENT_TIME arrivedAt = usecTimestampNow();
                        int flightTime = arrivedAt - sentAt;
                        
                        qDebug("got PacketType_VOXEL_DATA, sequence:%d flightTime:%d", sequence, flightTime);
                    }
                    
                    SharedNodePointer matchedNode = NodeList::getInstance()->sendingNodeForPacket(incomingPacket);
                    
                    if (matchedNode) {
                        // add this packet to our list of voxel packets and process them on the voxel processing
                        application->_octreeProcessor.queueReceivedPacket(matchedNode, incomingPacket);
                    }
                    
                    break;
                }
                case PacketTypeMetavoxelData:
                    nodeList->findNodeAndUpdateWithDataFromPacket(incomingPacket);
                    break;
                case PacketTypeBulkAvatarData:
                case PacketTypeKillAvatar:
                case PacketTypeAvatarIdentity:
                case PacketTypeAvatarBillboard: {
                    // update having heard from the avatar-mixer and record the bytes received
                    SharedNodePointer avatarMixer = nodeList->sendingNodeForPacket(incomingPacket);
                    
                    if (avatarMixer) {
                        avatarMixer->setLastHeardMicrostamp(usecTimestampNow());
                        avatarMixer->recordBytesReceived(incomingPacket.size());
                        
                        QMetaObject::invokeMethod(&application->getAvatarManager(), "processAvatarMixerDatagram",
                                                  Q_ARG(const QByteArray&, incomingPacket),
                                                  Q_ARG(const QWeakPointer<Node>&, avatarMixer));
                    }
                    
                    application->_bandwidthMeter.inputStream(BandwidthMeter::AVATARS).updateValue(incomingPacket.size());
                    break;
                }
                case PacketTypeDomainOAuthRequest: {
                    QDataStream readStream(incomingPacket);
                    readStream.skipRawData(numBytesForPacketHeader(incomingPacket));
                    
                    QUrl authorizationURL;
                    readStream >> authorizationURL;
                    
                    QMetaObject::invokeMethod(&OAuthWebViewHandler::getInstance(), "displayWebviewForAuthorizationURL",
                                              Q_ARG(const QUrl&, authorizationURL));
                    
                    break;
                }
                case PacketTypeMuteEnvironment: {
                    glm::vec3 position;
                    float radius;
                    
                    int headerSize = numBytesForPacketHeaderGivenPacketType(PacketTypeMuteEnvironment);
                    memcpy(&position, incomingPacket.constData() + headerSize, sizeof(glm::vec3));
                    memcpy(&radius, incomingPacket.constData() + headerSize + sizeof(glm::vec3), sizeof(float));
                    
                    if (glm::distance(Application::getInstance()->getAvatar()->getPosition(), position) < radius
                        && !Application::getInstance()->getAudio()->getMuted()) {
                        Application::getInstance()->getAudio()->toggleMute();
                    }
                    break;
                }
                case PacketTypeVoxelEditNack:
                    if (!Menu::getInstance()->isOptionChecked(MenuOption::DisableNackPackets)) {
                        application->_voxelEditSender.processNackPacket(incomingPacket);
                    }
                    break;
                case PacketTypeParticleEditNack:
                    if (!Menu::getInstance()->isOptionChecked(MenuOption::DisableNackPackets)) {
                        application->_particleEditSender.processNackPacket(incomingPacket);
                    }
                    break;
                case PacketTypeModelEditNack:
                    if (!Menu::getInstance()->isOptionChecked(MenuOption::DisableNackPackets)) {
                        application->_modelEditSender.processNackPacket(incomingPacket);
                    }
                    break;
                default:
                    nodeList->processNodeData(senderSockAddr, incomingPacket);
                    break;
            }
        }
    }
}