コード例 #1
0
ファイル: LimitedNodeList.cpp プロジェクト: Dreckinfeuer/hifi
bool LimitedNodeList::packetVersionAndHashMatch(const QByteArray& packet) {
    PacketType checkType = packetTypeForPacket(packet);
    int numPacketTypeBytes = numBytesArithmeticCodingFromBuffer(packet.data());

    if (packet[numPacketTypeBytes] != versionForPacketType(checkType)
            && checkType != PacketTypeStunResponse) {
        PacketType mismatchType = packetTypeForPacket(packet);

        static QMultiMap<QUuid, PacketType> versionDebugSuppressMap;

        QUuid senderUUID = uuidFromPacketHeader(packet);
        if (!versionDebugSuppressMap.contains(senderUUID, checkType)) {
            qCDebug(networking) << "Packet version mismatch on" << packetTypeForPacket(packet) << "- Sender"
                                << uuidFromPacketHeader(packet) << "sent" << qPrintable(QString::number(packet[numPacketTypeBytes])) << "but"
                                << qPrintable(QString::number(versionForPacketType(mismatchType))) << "expected.";

            emit packetVersionMismatch();

            versionDebugSuppressMap.insert(senderUUID, checkType);
        }

        return false;
    }

    if (!NON_VERIFIED_PACKETS.contains(checkType)) {
        // figure out which node this is from
        SharedNodePointer sendingNode = sendingNodeForPacket(packet);
        if (sendingNode) {
            // check if the md5 hash in the header matches the hash we would expect
            if (hashFromPacketHeader(packet) == hashForPacketAndConnectionUUID(packet, sendingNode->getConnectionSecret())) {
                return true;
            } else {
                static QMultiMap<QUuid, PacketType> hashDebugSuppressMap;

                QUuid senderUUID = uuidFromPacketHeader(packet);
                if (!hashDebugSuppressMap.contains(senderUUID, checkType)) {
                    qCDebug(networking) << "Packet hash mismatch on" << checkType << "- Sender"
                                        << uuidFromPacketHeader(packet);

                    hashDebugSuppressMap.insert(senderUUID, checkType);
                }
            }
        } else {
            static QString repeatedMessage
                = LogHandler::getInstance().addRepeatedMessageRegex("Packet of type \\d+ received from unknown node with UUID");

            qCDebug(networking) << "Packet of type" << checkType << "received from unknown node with UUID"
                                << qPrintable(uuidStringWithoutCurlyBraces(uuidFromPacketHeader(packet)));
        }
    } else {
        return true;
    }

    return false;
}
コード例 #2
0
int AvatarAudioRingBuffer::parseData(const QByteArray& packet) {
    timeGapStatsFrameReceived();
    updateDesiredJitterBufferFrames();

    _shouldLoopbackForNode = (packetTypeForPacket(packet) == PacketTypeMicrophoneAudioWithEcho);
    return PositionalAudioRingBuffer::parseData(packet);
}
コード例 #3
0
ファイル: LimitedNodeList.cpp プロジェクト: Dreckinfeuer/hifi
qint64 LimitedNodeList::writeUnverifiedDatagram(const QByteArray& datagram, const SharedNodePointer& destinationNode,
        const HifiSockAddr& overridenSockAddr) {
    if (destinationNode) {
        // if we don't have an ovveriden address, assume they want to send to the node's active socket
        const HifiSockAddr* destinationSockAddr = &overridenSockAddr;
        if (overridenSockAddr.isNull()) {
            if (destinationNode->getActiveSocket()) {
                // use the node's active socket as the destination socket
                destinationSockAddr = destinationNode->getActiveSocket();
            } else {
                // we don't have a socket to send to, return 0
                return 0;
            }
        }

        PacketType packetType = packetTypeForPacket(datagram);

        // optionally peform sequence number replacement in the header
        if (SEQUENCE_NUMBERED_PACKETS.contains(packetType)) {

            QByteArray datagramCopy = datagram;

            PacketSequenceNumber sequenceNumber = getNextSequenceNumberForPacket(destinationNode->getUUID(), packetType);
            replaceSequenceNumberInPacket(datagramCopy, sequenceNumber, packetType);

            // send the datagram with sequence number replaced in header
            return writeDatagram(datagramCopy, *destinationSockAddr);
        } else {
            return writeDatagram(datagram, *destinationSockAddr);
        }
    }

    // didn't have a destinationNode to send to, return 0
    return 0;
}
コード例 #4
0
ファイル: AudioMixer.cpp プロジェクト: BogusCurry/hifi
void AudioMixer::processDatagram(const QByteArray& dataByteArray, const HifiSockAddr& senderSockAddr) {
    // pull any new audio data from nodes off of the network stack
    PacketType mixerPacketType = packetTypeForPacket(dataByteArray);
    if (mixerPacketType == PacketTypeMicrophoneAudioNoEcho
        || mixerPacketType == PacketTypeMicrophoneAudioWithEcho
        || mixerPacketType == PacketTypeInjectAudio) {
        QUuid nodeUUID;
        deconstructPacketHeader(dataByteArray, nodeUUID);

        NodeList* nodeList = NodeList::getInstance();

        SharedNodePointer matchingNode = nodeList->nodeWithUUID(nodeUUID);

        if (matchingNode) {
            nodeList->updateNodeWithData(matchingNode.data(), senderSockAddr, dataByteArray);

            if (!matchingNode->getActiveSocket()) {
                // we don't have an active socket for this node, but they're talking to us
                // this means they've heard from us and can reply, let's assume public is active
                matchingNode->activatePublicSocket();
            }
        }
    } else {
        // let processNodeData handle it.
        NodeList::getInstance()->processNodeData(senderSockAddr, dataByteArray);
    }
}
コード例 #5
0
ファイル: Agent.cpp プロジェクト: hifialanwu/hifi
void Agent::processDatagram(const QByteArray& dataByteArray, const HifiSockAddr& senderSockAddr) {
    PacketType datagramPacketType = packetTypeForPacket(dataByteArray);
    if (datagramPacketType == PacketTypeJurisdiction) {
        int headerBytes = numBytesForPacketHeader(dataByteArray);
        // PacketType_JURISDICTION, first byte is the node type...
        switch (dataByteArray[headerBytes]) {
            case NodeType::VoxelServer:
                _scriptEngine.getVoxelsScriptingInterface()->getJurisdictionListener()->queueReceivedPacket(senderSockAddr,
                                                                                                            dataByteArray);
                break;
            case NodeType::ParticleServer:
                _scriptEngine.getParticlesScriptingInterface()->getJurisdictionListener()->queueReceivedPacket(senderSockAddr,
                                                                                                               dataByteArray);
                break;
        }
    } else if (datagramPacketType == PacketTypeParticleAddResponse) {
        // this will keep creatorTokenIDs to IDs mapped correctly
        Particle::handleAddParticleResponse(dataByteArray);
        
        // also give our local particle tree a chance to remap any internal locally created particles
        _particleTree.handleAddParticleResponse(dataByteArray);
    } else {
        NodeList::getInstance()->processNodeData(senderSockAddr, dataByteArray);
    }
}
コード例 #6
0
ファイル: AssignmentClient.cpp プロジェクト: kordero/hifi
void AssignmentClient::readPendingDatagrams() {
    NodeList* nodeList = NodeList::getInstance();
    
    QByteArray receivedPacket;
    HifiSockAddr senderSockAddr;
    
    while (nodeList->getNodeSocket().hasPendingDatagrams()) {
        receivedPacket.resize(nodeList->getNodeSocket().pendingDatagramSize());
        nodeList->getNodeSocket().readDatagram(receivedPacket.data(), receivedPacket.size(),
                                               senderSockAddr.getAddressPointer(), senderSockAddr.getPortPointer());
        
        if (nodeList->packetVersionAndHashMatch(receivedPacket)) {
            if (packetTypeForPacket(receivedPacket) == PacketTypeCreateAssignment) {
                // construct the deployed assignment from the packet data
                _currentAssignment = AssignmentFactory::unpackAssignment(receivedPacket);
                
                if (_currentAssignment) {
                    qDebug() << "Received an assignment -" << *_currentAssignment;
                    
                    // switch our nodelist domain IP and port to whoever sent us the assignment
                    
                    nodeList->getDomainInfo().setSockAddr(senderSockAddr);
                    nodeList->getDomainInfo().setAssignmentUUID(_currentAssignment->getUUID());
                    
                    qDebug() << "Destination IP for assignment is" << nodeList->getDomainInfo().getIP().toString();
                    
                    // start the deployed assignment
                    QThread* workerThread = new QThread(this);
                    
                    connect(workerThread, SIGNAL(started()), _currentAssignment, SLOT(run()));
                    
                    connect(_currentAssignment, SIGNAL(finished()), this, SLOT(assignmentCompleted()));
                    connect(_currentAssignment, SIGNAL(finished()), workerThread, SLOT(quit()));
                    connect(_currentAssignment, SIGNAL(finished()), _currentAssignment, SLOT(deleteLater()));
                    connect(workerThread, SIGNAL(finished()), workerThread, SLOT(deleteLater()));
                    
                    _currentAssignment->moveToThread(workerThread);
                    
                    // move the NodeList to the thread used for the _current assignment
                    nodeList->moveToThread(workerThread);
                    
                    // let the assignment handle the incoming datagrams for its duration
                    disconnect(&nodeList->getNodeSocket(), 0, this, 0);
                    connect(&nodeList->getNodeSocket(), &QUdpSocket::readyRead, _currentAssignment,
                            &ThreadedAssignment::readPendingDatagrams);
                    
                    // Starts an event loop, and emits workerThread->started()
                    workerThread->start();
                } else {
                    qDebug() << "Received an assignment that could not be unpacked. Re-requesting.";
                }
            } else {
                // have the NodeList attempt to handle it
                nodeList->processNodeData(senderSockAddr, receivedPacket);
            }
        }
    }
}
コード例 #7
0
int AudioMixerClientData::parseData(const QByteArray& packet) {
    PacketType packetType = packetTypeForPacket(packet);
    if (packetType == PacketTypeMicrophoneAudioWithEcho
        || packetType == PacketTypeMicrophoneAudioNoEcho
        || packetType == PacketTypeSilentAudioFrame) {

        // grab the AvatarAudioRingBuffer from the vector (or create it if it doesn't exist)
        AvatarAudioRingBuffer* avatarRingBuffer = getAvatarAudioRingBuffer();
        
        // read the first byte after the header to see if this is a stereo or mono buffer
        quint8 channelFlag = packet.at(numBytesForPacketHeader(packet));
        bool isStereo = channelFlag == 1;
        
        if (avatarRingBuffer && avatarRingBuffer->isStereo() != isStereo) {
            // there's a mismatch in the buffer channels for the incoming and current buffer
            // so delete our current buffer and create a new one
            _ringBuffers.removeOne(avatarRingBuffer);
            avatarRingBuffer->deleteLater();
            avatarRingBuffer = NULL;
        }

        if (!avatarRingBuffer) {
            // we don't have an AvatarAudioRingBuffer yet, so add it
            avatarRingBuffer = new AvatarAudioRingBuffer(isStereo);
            _ringBuffers.push_back(avatarRingBuffer);
        }

        // ask the AvatarAudioRingBuffer instance to parse the data
        avatarRingBuffer->parseData(packet);
    } else {
        // this is injected audio

        // grab the stream identifier for this injected audio
        QUuid streamIdentifier = QUuid::fromRfc4122(packet.mid(numBytesForPacketHeader(packet), NUM_BYTES_RFC4122_UUID));

        InjectedAudioRingBuffer* matchingInjectedRingBuffer = NULL;

        for (unsigned int i = 0; i < _ringBuffers.size(); i++) {
            if (_ringBuffers[i]->getType() == PositionalAudioRingBuffer::Injector
                && ((InjectedAudioRingBuffer*) _ringBuffers[i])->getStreamIdentifier() == streamIdentifier) {
                matchingInjectedRingBuffer = (InjectedAudioRingBuffer*) _ringBuffers[i];
            }
        }

        if (!matchingInjectedRingBuffer) {
            // we don't have a matching injected audio ring buffer, so add it
            matchingInjectedRingBuffer = new InjectedAudioRingBuffer(streamIdentifier);
            _ringBuffers.push_back(matchingInjectedRingBuffer);
        }

        matchingInjectedRingBuffer->parseData(packet);
    }

    return 0;
}
コード例 #8
0
ファイル: PacketHeaders.cpp プロジェクト: BogusCurry/hifi
bool packetVersionMatch(const QByteArray& packet) {
    // currently this just checks if the version in the packet matches our return from versionForPacketType
    // may need to be expanded in the future for types and versions that take > than 1 byte
    
    if (packet[1] == versionForPacketType(packetTypeForPacket(packet)) || packetTypeForPacket(packet) == PacketTypeStunResponse) {
        return true;
    } else {
        PacketType mismatchType = packetTypeForPacket(packet);
        int numPacketTypeBytes = arithmeticCodingValueFromBuffer(packet.data());
       
        QUuid nodeUUID;
        deconstructPacketHeader(packet, nodeUUID);
        
        qDebug() << "Packet mismatch on" << packetTypeForPacket(packet) << "- Sender"
            << nodeUUID << "sent" << qPrintable(QString::number(packet[numPacketTypeBytes])) << "but"
            << qPrintable(QString::number(versionForPacketType(mismatchType))) << "expected.";

        return false;
    }
}
コード例 #9
0
ファイル: LimitedNodeList.cpp プロジェクト: Dreckinfeuer/hifi
qint64 LimitedNodeList::writeDatagram(const QByteArray& datagram,
                                      const SharedNodePointer& destinationNode,
                                      const HifiSockAddr& overridenSockAddr) {
    if (destinationNode) {
        PacketType packetType = packetTypeForPacket(datagram);

        if (NON_VERIFIED_PACKETS.contains(packetType)) {
            return writeUnverifiedDatagram(datagram, destinationNode, overridenSockAddr);
        }

        // if we don't have an overridden address, assume they want to send to the node's active socket
        const HifiSockAddr* destinationSockAddr = &overridenSockAddr;
        if (overridenSockAddr.isNull()) {
            if (destinationNode->getActiveSocket()) {
                // use the node's active socket as the destination socket
                destinationSockAddr = destinationNode->getActiveSocket();
            } else {
                // we don't have a socket to send to, return 0
                return 0;
            }
        }

        QByteArray datagramCopy = datagram;

        // if we're here and the connection secret is null, debug out - this could be a problem
        if (destinationNode->getConnectionSecret().isNull()) {
            qDebug() << "LimitedNodeList::writeDatagram called for verified datagram with null connection secret for"
                     << "destination node" << destinationNode->getUUID() << " - this is either not secure or will cause"
                     << "this packet to be unverifiable on the receiving side.";
        }

        // perform replacement of hash and optionally also sequence number in the header
        if (SEQUENCE_NUMBERED_PACKETS.contains(packetType)) {
            PacketSequenceNumber sequenceNumber = getNextSequenceNumberForPacket(destinationNode->getUUID(), packetType);
            replaceHashAndSequenceNumberInPacket(datagramCopy, destinationNode->getConnectionSecret(),
                                                 sequenceNumber, packetType);
        } else {
            replaceHashInPacket(datagramCopy, destinationNode->getConnectionSecret(), packetType);
        }

        emit dataSent(destinationNode->getType(), datagram.size());
        auto bytesWritten = writeDatagram(datagramCopy, *destinationSockAddr);
        // Keep track of per-destination-node bandwidth
        destinationNode->recordBytesSent(bytesWritten);
        return bytesWritten;
    }

    // didn't have a destinationNode to send to, return 0
    return 0;
}
コード例 #10
0
ファイル: AvatarHashMap.cpp プロジェクト: ey6es/hifi
void AvatarHashMap::processAvatarMixerDatagram(const QByteArray& datagram, const QWeakPointer<Node>& mixerWeakPointer) {
    switch (packetTypeForPacket(datagram)) {
        case PacketTypeBulkAvatarData:
            processAvatarDataPacket(datagram, mixerWeakPointer);
            break;
        case PacketTypeAvatarIdentity:
            processAvatarIdentityPacket(datagram, mixerWeakPointer);
            break;
        case PacketTypeAvatarBillboard:
            processAvatarBillboardPacket(datagram, mixerWeakPointer);
            break;
        case PacketTypeKillAvatar:
            processKillAvatar(datagram);
            break;
        default:
            break;
    }
}
コード例 #11
0
ファイル: AudioMixerClientData.cpp プロジェクト: kordero/hifi
int AudioMixerClientData::parseData(const QByteArray& packet) {
    PacketType packetType = packetTypeForPacket(packet);
    if (packetType == PacketTypeMicrophoneAudioWithEcho
        || packetType == PacketTypeMicrophoneAudioNoEcho
        || packetType == PacketTypeSilentAudioFrame) {

        // grab the AvatarAudioRingBuffer from the vector (or create it if it doesn't exist)
        AvatarAudioRingBuffer* avatarRingBuffer = getAvatarAudioRingBuffer();

        if (!avatarRingBuffer) {
            // we don't have an AvatarAudioRingBuffer yet, so add it
            avatarRingBuffer = new AvatarAudioRingBuffer();
            _ringBuffers.push_back(avatarRingBuffer);
        }

        // ask the AvatarAudioRingBuffer instance to parse the data
        avatarRingBuffer->parseData(packet);
    } else {
        // this is injected audio

        // grab the stream identifier for this injected audio
        QUuid streamIdentifier = QUuid::fromRfc4122(packet.mid(numBytesForPacketHeader(packet), NUM_BYTES_RFC4122_UUID));

        InjectedAudioRingBuffer* matchingInjectedRingBuffer = NULL;

        for (unsigned int i = 0; i < _ringBuffers.size(); i++) {
            if (_ringBuffers[i]->getType() == PositionalAudioRingBuffer::Injector
                && ((InjectedAudioRingBuffer*) _ringBuffers[i])->getStreamIdentifier() == streamIdentifier) {
                matchingInjectedRingBuffer = (InjectedAudioRingBuffer*) _ringBuffers[i];
            }
        }

        if (!matchingInjectedRingBuffer) {
            // we don't have a matching injected audio ring buffer, so add it
            matchingInjectedRingBuffer = new InjectedAudioRingBuffer(streamIdentifier);
            _ringBuffers.push_back(matchingInjectedRingBuffer);
        }

        matchingInjectedRingBuffer->parseData(packet);
    }

    return 0;
}
コード例 #12
0
void MetavoxelServer::readPendingDatagrams() {
    QByteArray receivedPacket;
    HifiSockAddr senderSockAddr;
    
    NodeList* nodeList = NodeList::getInstance();
    
    while (readAvailableDatagram(receivedPacket, senderSockAddr)) {
        if (nodeList->packetVersionAndHashMatch(receivedPacket)) {
            switch (packetTypeForPacket(receivedPacket)) {
                case PacketTypeMetavoxelData:
                    nodeList->findNodeAndUpdateWithDataFromPacket(receivedPacket);
                    break;
                
                default:
                    nodeList->processNodeData(senderSockAddr, receivedPacket);
                    break;
            }
        }
    }
}
コード例 #13
0
ファイル: LimitedNodeList.cpp プロジェクト: softwarekid/hifi
QByteArray LimitedNodeList::constructPingReplyPacket(const QByteArray& pingPacket, const QUuid& packetHeaderID) {
    QDataStream pingPacketStream(pingPacket);
    pingPacketStream.skipRawData(numBytesForPacketHeader(pingPacket));
    
    PingType_t typeFromOriginalPing;
    pingPacketStream >> typeFromOriginalPing;
    
    quint64 timeFromOriginalPing;
    pingPacketStream >> timeFromOriginalPing;
    
    PacketType replyType = (packetTypeForPacket(pingPacket) == PacketTypePing)
        ? PacketTypePingReply : PacketTypeUnverifiedPingReply;
    
    QByteArray replyPacket = byteArrayWithPopulatedHeader(replyType, packetHeaderID);
    QDataStream packetStream(&replyPacket, QIODevice::Append);
    
    packetStream << typeFromOriginalPing << timeFromOriginalPing << usecTimestampNow();
    
    return replyPacket;
}
コード例 #14
0
ファイル: AudioMixer.cpp プロジェクト: kordero/hifi
void AudioMixer::readPendingDatagrams() {
    QByteArray receivedPacket;
    HifiSockAddr senderSockAddr;
    NodeList* nodeList = NodeList::getInstance();
    
    while (readAvailableDatagram(receivedPacket, senderSockAddr)) {
        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) {
                
                nodeList->findNodeAndUpdateWithDataFromPacket(receivedPacket);
            } else {
                // let processNodeData handle it.
                nodeList->processNodeData(senderSockAddr, receivedPacket);
            }
        }
    }
}
コード例 #15
0
ファイル: LimitedNodeList.cpp プロジェクト: Dreckinfeuer/hifi
int LimitedNodeList::updateNodeWithDataFromPacket(const SharedNodePointer& matchingNode, const QByteArray &packet) {
    QMutexLocker locker(&matchingNode->getMutex());

    matchingNode->setLastHeardMicrostamp(usecTimestampNow());

    // if this was a sequence numbered packet we should store the last seq number for
    // a packet of this type for this node
    PacketType packetType = packetTypeForPacket(packet);
    if (SEQUENCE_NUMBERED_PACKETS.contains(packetType)) {
        matchingNode->setLastSequenceNumberForPacketType(sequenceNumberFromHeader(packet, packetType), packetType);
    }

    NodeData* linkedData = matchingNode->getLinkedData();
    if (!linkedData && linkedDataCreateCallback) {
        linkedDataCreateCallback(matchingNode.data());
    }

    if (linkedData) {
        QMutexLocker linkedDataLocker(&linkedData->getMutex());
        return linkedData->parseData(packet);
    }
    return 0;
}
コード例 #16
0
void OctreeServerDatagramProcessor::readPendingDatagrams() {

    HifiSockAddr senderSockAddr;
    static QByteArray incomingPacket;

    // read everything that is available
    while (_nodeSocket.hasPendingDatagrams()) {
        incomingPacket.resize(_nodeSocket.pendingDatagramSize());

        // just get this packet off the stack
        _nodeSocket.readDatagram(incomingPacket.data(), incomingPacket.size(),
                                 senderSockAddr.getAddressPointer(), senderSockAddr.getPortPointer());

        PacketType packetType = packetTypeForPacket(incomingPacket);
        if (packetType == PacketTypePing) {
            DependencyManager::get<NodeList>()->processNodeData(senderSockAddr, incomingPacket);
            return; // don't emit
        }

        // emit the signal to tell AudioMixer it needs to process a packet
        emit packetRequiresProcessing(incomingPacket, senderSockAddr);
    }
}
コード例 #17
0
ファイル: AudioMixer.cpp プロジェクト: JeroMiya/hifi
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 {
コード例 #18
0
int PositionalAudioRingBuffer::parseData(const QByteArray& packet) {

    // skip the packet header (includes the source UUID)
    int readBytes = numBytesForPacketHeader(packet);

    readBytes += parsePositionalData(packet.mid(readBytes));

    if (packetTypeForPacket(packet) == PacketTypeSilentAudioFrame) {
        // this source had no audio to send us, but this counts as a packet
        // write silence equivalent to the number of silent samples they just sent us
        int16_t numSilentSamples;

        memcpy(&numSilentSamples, packet.data() + readBytes, sizeof(int16_t));

        readBytes += sizeof(int16_t);

        addSilentFrame(numSilentSamples);
    } else {
        // there is audio data to read
        readBytes += writeData(packet.data() + readBytes, packet.size() - readBytes);
    }

    return readBytes;
}
コード例 #19
0
void OctreeRenderer::processDatagram(const QByteArray& dataByteArray, const SharedNodePointer& sourceNode) {
    bool extraDebugging = false;
    
    if (extraDebugging) {
        qCDebug(octree) << "OctreeRenderer::processDatagram()";
    }

    if (!_tree) {
        qCDebug(octree) << "OctreeRenderer::processDatagram() called before init, calling init()...";
        this->init();
    }

    bool showTimingDetails = false; // Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
    PerformanceWarning warn(showTimingDetails, "OctreeRenderer::processDatagram()",showTimingDetails);
    
    unsigned int packetLength = dataByteArray.size();
    PacketType command = packetTypeForPacket(dataByteArray);
    unsigned int numBytesPacketHeader = numBytesForPacketHeader(dataByteArray);
    QUuid sourceUUID = uuidFromPacketHeader(dataByteArray);
    PacketType expectedType = getExpectedPacketType();
    // packetVersion is the second byte
    PacketVersion packetVersion = dataByteArray[1];
    
    if(command == expectedType) {
        PerformanceWarning warn(showTimingDetails, "OctreeRenderer::processDatagram expected PacketType", showTimingDetails);
        // if we are getting inbound packets, then our tree is also viewing, and we should remember that fact.
        _tree->setIsViewing(true);

        const unsigned char* dataAt = reinterpret_cast<const unsigned char*>(dataByteArray.data()) + numBytesPacketHeader;

        OCTREE_PACKET_FLAGS flags = (*(OCTREE_PACKET_FLAGS*)(dataAt));
        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);

        bool packetIsColored = oneAtBit(flags, PACKET_IS_COLOR_BIT);
        bool packetIsCompressed = oneAtBit(flags, PACKET_IS_COMPRESSED_BIT);
        
        OCTREE_PACKET_SENT_TIME arrivedAt = usecTimestampNow();
        int clockSkew = sourceNode ? sourceNode->getClockSkewUsec() : 0;
        int flightTime = arrivedAt - sentAt + clockSkew;

        OCTREE_PACKET_INTERNAL_SECTION_SIZE sectionLength = 0;
        unsigned int dataBytes = packetLength - (numBytesPacketHeader + OCTREE_PACKET_EXTRA_HEADERS_SIZE);

        if (extraDebugging) {
            qCDebug(octree, "OctreeRenderer::processDatagram() ... Got Packet Section"
                   " color:%s compressed:%s sequence: %u flight:%d usec size:%u data:%u",
                   debug::valueOf(packetIsColored), debug::valueOf(packetIsCompressed),
                   sequence, flightTime, packetLength, dataBytes);
        }
        
        int subsection = 1;
        while (dataBytes > 0) {
            if (packetIsCompressed) {
                if (dataBytes > sizeof(OCTREE_PACKET_INTERNAL_SECTION_SIZE)) {
                    sectionLength = (*(OCTREE_PACKET_INTERNAL_SECTION_SIZE*)dataAt);
                    dataAt += sizeof(OCTREE_PACKET_INTERNAL_SECTION_SIZE);
                    dataBytes -= sizeof(OCTREE_PACKET_INTERNAL_SECTION_SIZE);
                } else {
                    sectionLength = 0;
                    dataBytes = 0; // stop looping something is wrong
                }
            } else {
                sectionLength = dataBytes;
            }
            
            if (sectionLength) {
                // ask the VoxelTree to read the bitstream into the tree
                ReadBitstreamToTreeParams args(packetIsColored ? WANT_COLOR : NO_COLOR, WANT_EXISTS_BITS, NULL, 
                                                sourceUUID, sourceNode, false, packetVersion);
                _tree->lockForWrite();
                OctreePacketData packetData(packetIsCompressed);
                packetData.loadFinalizedContent(dataAt, sectionLength);
                if (extraDebugging) {
                    qCDebug(octree, "OctreeRenderer::processDatagram() ... Got Packet Section"
                           " color:%s compressed:%s sequence: %u flight:%d usec size:%u data:%u"
                           " subsection:%d sectionLength:%d uncompressed:%d",
                           debug::valueOf(packetIsColored), debug::valueOf(packetIsCompressed),
                           sequence, flightTime, packetLength, dataBytes, subsection, sectionLength,
                           packetData.getUncompressedSize());
                }
                if (extraDebugging) {
                    qCDebug(octree) << "OctreeRenderer::processDatagram() ******* START _tree->readBitstreamToTree()...";
                }
                _tree->readBitstreamToTree(packetData.getUncompressedData(), packetData.getUncompressedSize(), args);
                if (extraDebugging) {
                    qCDebug(octree) << "OctreeRenderer::processDatagram() ******* END _tree->readBitstreamToTree()...";
                }
                _tree->unlock();
            
                dataBytes -= sectionLength;
                dataAt += sectionLength;
            }
        }
        subsection++;
    }
}
コード例 #20
0
ファイル: NodeList.cpp プロジェクト: VR-cdrone/hifi
void NodeList::processNodeData(const HifiSockAddr& senderSockAddr, const QByteArray& packet) {
    switch (packetTypeForPacket(packet)) {
        case PacketTypeDomainList: {
            processDomainServerList(packet);
            break;
        }
        case PacketTypeDomainServerRequireDTLS: {
            _domainHandler.parseDTLSRequirementPacket(packet);
            break;
        }
        case PacketTypeIceServerHeartbeatResponse: {
            _domainHandler.processICEResponsePacket(packet);
            break;
        }
        case PacketTypePing: {
            // send back a reply
            SharedNodePointer matchingNode = sendingNodeForPacket(packet);
            if (matchingNode) {
                matchingNode->setLastHeardMicrostamp(usecTimestampNow());
                QByteArray replyPacket = constructPingReplyPacket(packet);
                writeDatagram(replyPacket, matchingNode, senderSockAddr);
                
                // If we don't have a symmetric socket for this node and this socket doesn't match
                // what we have for public and local then set it as the symmetric.
                // This allows a server on a reachable port to communicate with nodes on symmetric NATs
                if (matchingNode->getSymmetricSocket().isNull()) {
                    if (senderSockAddr != matchingNode->getLocalSocket() && senderSockAddr != matchingNode->getPublicSocket()) {
                        matchingNode->setSymmetricSocket(senderSockAddr);
                    }
                }
            }
            
            break;
        }
        case PacketTypePingReply: {
            SharedNodePointer sendingNode = sendingNodeForPacket(packet);
            
            if (sendingNode) {
                sendingNode->setLastHeardMicrostamp(usecTimestampNow());
                
                // activate the appropriate socket for this node, if not yet updated
                activateSocketFromNodeCommunication(packet, sendingNode);
                
                // set the ping time for this node for stat collection
                timePingReply(packet, sendingNode);
            }
            
            break;
        }
        case PacketTypeUnverifiedPing: {
            // send back a reply
            QByteArray replyPacket = constructPingReplyPacket(packet, _domainHandler.getICEClientID());
            writeUnverifiedDatagram(replyPacket, senderSockAddr);
            break;
        }
        case PacketTypeUnverifiedPingReply: {
            qDebug() << "Received reply from domain-server on" << senderSockAddr;
            
            // for now we're unsafely assuming this came back from the domain
            if (senderSockAddr == _domainHandler.getICEPeer().getLocalSocket()) {
                qDebug() << "Connecting to domain using local socket";
                _domainHandler.activateICELocalSocket();
            } else if (senderSockAddr == _domainHandler.getICEPeer().getPublicSocket()) {
                qDebug() << "Conecting to domain using public socket";
                _domainHandler.activateICEPublicSocket();
            } else {
                qDebug() << "Reply does not match either local or public socket for domain. Will not connect.";
            }
        }
        case PacketTypeStunResponse: {
            // a STUN packet begins with 00, we've checked the second zero with packetVersionMatch
            // pass it along so it can be processed into our public address and port
            processSTUNResponse(packet);
            break;
        }
        default:
            LimitedNodeList::processNodeData(senderSockAddr, packet);
            break;
    }
}
コード例 #21
0
ファイル: Agent.cpp プロジェクト: JeroMiya/hifi
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);
            }
        }
    }
}
コード例 #22
0
ファイル: VoxelPacketProcessor.cpp プロジェクト: Chris7/hifi
void VoxelPacketProcessor::processPacket(const SharedNodePointer& sendingNode, const QByteArray& packet) {
    PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
                            "VoxelPacketProcessor::processPacket()");
    
    QByteArray mutablePacket = packet;

    const int WAY_BEHIND = 300;

    if (packetsToProcessCount() > WAY_BEHIND && Application::getInstance()->getLogger()->extraDebugging()) {
        qDebug("VoxelPacketProcessor::processPacket() packets to process=%d", packetsToProcessCount());
    }
    ssize_t messageLength = mutablePacket.size();

    Application* app = Application::getInstance();
    bool wasStatsPacket = false;


    // check to see if the UI thread asked us to kill the voxel tree. since we're the only thread allowed to do that
    if (app->_wantToKillLocalVoxels) {
        app->_voxels.killLocalVoxels();
        app->_wantToKillLocalVoxels = false;
    }
    
    PacketType voxelPacketType = packetTypeForPacket(mutablePacket);

    // note: PacketType_OCTREE_STATS can have PacketType_VOXEL_DATA
    // immediately following them inside the same packet. So, we process the PacketType_OCTREE_STATS first
    // then process any remaining bytes as if it was another packet
    if (voxelPacketType == PacketTypeOctreeStats) {

        int statsMessageLength = app->parseOctreeStats(mutablePacket, sendingNode);
        wasStatsPacket = true;
        if (messageLength > statsMessageLength) {
            mutablePacket = mutablePacket.mid(statsMessageLength);
            
            // TODO: this does not look correct, the goal is to test the packet version for the piggyback, but
            //       this is testing the version and hash of the original packet
            if (!NodeList::getInstance()->packetVersionAndHashMatch(packet)) {
                return; // bail since piggyback data doesn't match our versioning
            }
        } else {
            // Note... stats packets don't have sequence numbers, so we don't want to send those to trackIncomingVoxelPacket()
            return; // bail since no piggyback data
        }
    } // fall through to piggyback message
    
    voxelPacketType = packetTypeForPacket(mutablePacket);
    
    if (Menu::getInstance()->isOptionChecked(MenuOption::Voxels)) {
        app->trackIncomingVoxelPacket(mutablePacket, sendingNode, wasStatsPacket);

        if (sendingNode) {

            switch(voxelPacketType) {
                case PacketTypeParticleErase: {
                    app->_particles.processEraseMessage(mutablePacket, sendingNode);
                } break;

                case PacketTypeParticleData: {
                    app->_particles.processDatagram(mutablePacket, sendingNode);
                } break;

                case PacketTypeEnvironmentData: {
                    app->_environment.parseData(*sendingNode->getActiveSocket(), mutablePacket);
                } break;

                default : {
                    app->_voxels.setDataSourceUUID(sendingNode->getUUID());
                    app->_voxels.parseData(mutablePacket);
                    app->_voxels.setDataSourceUUID(QUuid());
                } break;
            }
        }
    }
}
コード例 #23
0
void OctreeInboundPacketProcessor::processPacket(const SharedNodePointer& sendingNode, const QByteArray& packet) {
    if (_shuttingDown) {
        qDebug() << "OctreeInboundPacketProcessor::processPacket() while shutting down... ignoring incoming packet";
        return;
    }

    bool debugProcessPacket = _myServer->wantsVerboseDebug();

    if (debugProcessPacket) {
        qDebug("OctreeInboundPacketProcessor::processPacket() packetData=%p packetLength=%d", &packet, packet.size());
    }

    int numBytesPacketHeader = numBytesForPacketHeader(packet);


    // Ask our tree subclass if it can handle the incoming packet...
    PacketType packetType = packetTypeForPacket(packet);
    if (_myServer->getOctree()->handlesEditPacketType(packetType)) {
        PerformanceWarning warn(debugProcessPacket, "processPacket KNOWN TYPE",debugProcessPacket);
        _receivedPacketCount++;
        
        const unsigned char* packetData = reinterpret_cast<const unsigned char*>(packet.data());

        unsigned short int sequence = (*((unsigned short int*)(packetData + numBytesPacketHeader)));
        quint64 sentAt = (*((quint64*)(packetData + numBytesPacketHeader + sizeof(sequence))));
        quint64 arrivedAt = usecTimestampNow();
        if (sentAt > arrivedAt) {
            if (debugProcessPacket || _myServer->wantsDebugReceiving()) {
                qDebug() << "unreasonable sentAt=" << sentAt << " usecs";
                qDebug() << "setting sentAt to arrivedAt=" << arrivedAt << " usecs";
            }
            sentAt = arrivedAt;
        }
        quint64 transitTime = arrivedAt - sentAt;
        int editsInPacket = 0;
        quint64 processTime = 0;
        quint64 lockWaitTime = 0;

        if (debugProcessPacket || _myServer->wantsDebugReceiving()) {
            qDebug() << "PROCESSING THREAD: got '" << packetType << "' packet - " << _receivedPacketCount << " command from client";
            qDebug() << "    receivedBytes=" << packet.size();
            qDebug() << "         sequence=" << sequence;
            qDebug() << "           sentAt=" << sentAt << " usecs";
            qDebug() << "        arrivedAt=" << arrivedAt << " usecs";
            qDebug() << "      transitTime=" << transitTime << " usecs";
            qDebug() << "      sendingNode->getClockSkewUsec()=" << sendingNode->getClockSkewUsec() << " usecs";
            
            
        }
        
        if (debugProcessPacket) {
            qDebug() << "    numBytesPacketHeader=" << numBytesPacketHeader;
            qDebug() << "    sizeof(sequence)=" << sizeof(sequence);
            qDebug() << "    sizeof(sentAt)=" << sizeof(sentAt);
        }
        
        int atByte = numBytesPacketHeader + sizeof(sequence) + sizeof(sentAt);

        if (debugProcessPacket) {
            qDebug() << "    atByte=" << atByte;
            qDebug() << "    packet.size()=" << packet.size();
            if (atByte >= packet.size()) {
                qDebug() << "    ----- UNEXPECTED ---- got a packet without any edit details!!!! --------";
            }
        }
        

        unsigned char* editData = (unsigned char*)&packetData[atByte];
        while (atByte < packet.size()) {
        
            int maxSize = packet.size() - atByte;

            if (debugProcessPacket) {
                qDebug() << " --- inside while loop ---";
                qDebug() << "    maxSize=" << maxSize;
                qDebug("OctreeInboundPacketProcessor::processPacket() %c "
                       "packetData=%p packetLength=%d editData=%p atByte=%d maxSize=%d",
                        packetType, packetData, packet.size(), editData, atByte, maxSize);
            }

            quint64 startLock = usecTimestampNow();
            _myServer->getOctree()->lockForWrite();
            quint64 startProcess = usecTimestampNow();
            int editDataBytesRead = _myServer->getOctree()->processEditPacketData(packetType,
                                                                                  reinterpret_cast<const unsigned char*>(packet.data()),
                                                                                  packet.size(),
                                                                                  editData, maxSize, sendingNode);

            if (debugProcessPacket) {
                qDebug() << "OctreeInboundPacketProcessor::processPacket() after processEditPacketData()..."
                                << "editDataBytesRead=" << editDataBytesRead;
            }

            _myServer->getOctree()->unlock();
            quint64 endProcess = usecTimestampNow();

            editsInPacket++;
            quint64 thisProcessTime = endProcess - startProcess;
            quint64 thisLockWaitTime = startProcess - startLock;
            processTime += thisProcessTime;
            lockWaitTime += thisLockWaitTime;

            // skip to next edit record in the packet
            editData += editDataBytesRead;
            atByte += editDataBytesRead;

            if (debugProcessPacket) {
                qDebug() << "    editDataBytesRead=" << editDataBytesRead;
                qDebug() << "    AFTER processEditPacketData atByte=" << atByte;
                qDebug() << "    AFTER processEditPacketData packet.size()=" << packet.size();
            }

        }

        if (debugProcessPacket) {
            qDebug("OctreeInboundPacketProcessor::processPacket() DONE LOOPING FOR %c "
                   "packetData=%p packetLength=%d editData=%p atByte=%d",
                    packetType, packetData, packet.size(), editData, atByte);
        }

        // Make sure our Node and NodeList knows we've heard from this node.
        QUuid& nodeUUID = DEFAULT_NODE_ID_REF;
        if (sendingNode) {
            sendingNode->setLastHeardMicrostamp(usecTimestampNow());
            nodeUUID = sendingNode->getUUID();
            if (debugProcessPacket) {
                qDebug() << "sender has uuid=" << nodeUUID;
            }
        } else {
            if (debugProcessPacket) {
                qDebug() << "sender has no known nodeUUID.";
            }
        }
        trackInboundPacket(nodeUUID, sequence, transitTime, editsInPacket, processTime, lockWaitTime);
    } else {
        qDebug("unknown packet ignored... packetType=%d", packetType);
    }
}
コード例 #24
0
int InboundAudioStream::parseData(const QByteArray& packet) {

    PacketType packetType = packetTypeForPacket(packet);
    QUuid senderUUID = uuidFromPacketHeader(packet);

    // parse header 
    int numBytesHeader = numBytesForPacketHeader(packet);
    const char* sequenceAt = packet.constData() + numBytesHeader;
    int readBytes = numBytesHeader;

    // parse sequence number and track it
    quint16 sequence = *(reinterpret_cast<const quint16*>(sequenceAt));
    readBytes += sizeof(quint16);
    SequenceNumberStats::ArrivalInfo arrivalInfo = _incomingSequenceNumberStats.sequenceNumberReceived(sequence, senderUUID);

    frameReceivedUpdateTimingStats();

    // TODO: handle generalized silent packet here?????

    // parse the info after the seq number and before the audio data.(the stream properties)
    int numAudioSamples;
    readBytes += parseStreamProperties(packetType, packet.mid(readBytes), numAudioSamples);

    // handle this packet based on its arrival status.
    // For now, late packets are ignored.  It may be good in the future to insert the late audio frame
    // into the ring buffer to fill in the missing frame if it hasn't been mixed yet.
    switch (arrivalInfo._status) {
        case SequenceNumberStats::Early: {
            int packetsDropped = arrivalInfo._seqDiffFromExpected;
            writeSamplesForDroppedPackets(packetsDropped * numAudioSamples);
            // fall through to OnTime case
        }
        case SequenceNumberStats::OnTime: {
            readBytes += parseAudioData(packetType, packet.mid(readBytes), numAudioSamples);
            break;
        }
        default: {
            break;
        }
    }

    int framesAvailable = _ringBuffer.framesAvailable();
    // if this stream was starved, check if we're still starved.
    if (_isStarved && framesAvailable >= _desiredJitterBufferFrames) {
        _isStarved = false;
    }
    // if the ringbuffer exceeds the desired size by more than the threshold specified,
    // drop the oldest frames so the ringbuffer is down to the desired size.
    if (framesAvailable > _desiredJitterBufferFrames + _maxFramesOverDesired) {
        int framesToDrop = framesAvailable - (_desiredJitterBufferFrames + DESIRED_JITTER_BUFFER_FRAMES_PADDING);
        _ringBuffer.shiftReadPosition(framesToDrop * _ringBuffer.getNumFrameSamples());
        
        _framesAvailableStat.reset();
        _currentJitterBufferFrames = 0;

        _oldFramesDropped += framesToDrop;
    }

    framesAvailableChanged();

    return readBytes;
}
コード例 #25
0
ファイル: PacketHeaders.cpp プロジェクト: Barnold1953/hifi
int numBytesForPacketHeader(const char* packet) {
    // returns the number of bytes used for the type, version, and UUID
    return numBytesArithmeticCodingFromBuffer(packet)
    + numHashBytesInPacketHeaderGivenPacketType(packetTypeForPacket(packet))
    + NUM_STATIC_HEADER_BYTES;
}
コード例 #26
0
int AudioMixerClientData::parseData(const QByteArray& packet) {

    // parse sequence number for this packet
    int numBytesPacketHeader = numBytesForPacketHeader(packet);
    const char* sequenceAt = packet.constData() + numBytesPacketHeader;
    quint16 sequence = *(reinterpret_cast<const quint16*>(sequenceAt));

    PacketType packetType = packetTypeForPacket(packet);
    if (packetType == PacketTypeMicrophoneAudioWithEcho
        || packetType == PacketTypeMicrophoneAudioNoEcho
        || packetType == PacketTypeSilentAudioFrame) {

        _incomingAvatarAudioSequenceNumberStats.sequenceNumberReceived(sequence);

        // grab the AvatarAudioRingBuffer from the vector (or create it if it doesn't exist)
        AvatarAudioRingBuffer* avatarRingBuffer = getAvatarAudioRingBuffer();
        
        // read the first byte after the header to see if this is a stereo or mono buffer
        quint8 channelFlag = packet.at(numBytesForPacketHeader(packet) + sizeof(quint16));
        bool isStereo = channelFlag == 1;
        
        if (avatarRingBuffer && avatarRingBuffer->isStereo() != isStereo) {
            // there's a mismatch in the buffer channels for the incoming and current buffer
            // so delete our current buffer and create a new one
            _ringBuffers.removeOne(avatarRingBuffer);
            avatarRingBuffer->deleteLater();
            avatarRingBuffer = NULL;
        }

        if (!avatarRingBuffer) {
            // we don't have an AvatarAudioRingBuffer yet, so add it
            avatarRingBuffer = new AvatarAudioRingBuffer(isStereo, AudioMixer::getUseDynamicJitterBuffers());
            _ringBuffers.push_back(avatarRingBuffer);
        }

        // ask the AvatarAudioRingBuffer instance to parse the data
        avatarRingBuffer->parseData(packet);
    } else if (packetType == PacketTypeInjectAudio) {
        // this is injected audio

        // grab the stream identifier for this injected audio
        QUuid streamIdentifier = QUuid::fromRfc4122(packet.mid(numBytesForPacketHeader(packet) + sizeof(quint16), NUM_BYTES_RFC4122_UUID));

        if (!_incomingInjectedAudioSequenceNumberStatsMap.contains(streamIdentifier)) {
            _incomingInjectedAudioSequenceNumberStatsMap.insert(streamIdentifier, SequenceNumberStats(INCOMING_SEQ_STATS_HISTORY_LENGTH));
        }
        _incomingInjectedAudioSequenceNumberStatsMap[streamIdentifier].sequenceNumberReceived(sequence);

        InjectedAudioRingBuffer* matchingInjectedRingBuffer = NULL;

        for (int i = 0; i < _ringBuffers.size(); i++) {
            if (_ringBuffers[i]->getType() == PositionalAudioRingBuffer::Injector
                && ((InjectedAudioRingBuffer*) _ringBuffers[i])->getStreamIdentifier() == streamIdentifier) {
                matchingInjectedRingBuffer = (InjectedAudioRingBuffer*) _ringBuffers[i];
            }
        }

        if (!matchingInjectedRingBuffer) {
            // we don't have a matching injected audio ring buffer, so add it
            matchingInjectedRingBuffer = new InjectedAudioRingBuffer(streamIdentifier, AudioMixer::getUseDynamicJitterBuffers());
            _ringBuffers.push_back(matchingInjectedRingBuffer);
        }

        matchingInjectedRingBuffer->parseData(packet);
    } else if (packetType == PacketTypeAudioStreamStats) {

        const char* dataAt = packet.data();

        // skip over header, appendFlag, and num stats packed
        dataAt += (numBytesPacketHeader + sizeof(quint8) + sizeof(quint16));

        // read the downstream audio stream stats
        memcpy(&_downstreamAudioStreamStats, dataAt, sizeof(AudioStreamStats));
    }

    return 0;
}
コード例 #27
0
void OctreePacketProcessor::processPacket(const SharedNodePointer& sendingNode, const QByteArray& packet) {
    PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
                            "OctreePacketProcessor::processPacket()");
    
    QByteArray mutablePacket = packet;

    const int WAY_BEHIND = 300;

    if (packetsToProcessCount() > WAY_BEHIND && Application::getInstance()->getLogger()->extraDebugging()) {
        qDebug("OctreePacketProcessor::processPacket() packets to process=%d", packetsToProcessCount());
    }
    int messageLength = mutablePacket.size();

    Application* app = Application::getInstance();
    bool wasStatsPacket = false;


    PacketType voxelPacketType = packetTypeForPacket(mutablePacket);
    
    // note: PacketType_OCTREE_STATS can have PacketType_VOXEL_DATA
    // immediately following them inside the same packet. So, we process the PacketType_OCTREE_STATS first
    // then process any remaining bytes as if it was another packet
    if (voxelPacketType == PacketTypeOctreeStats) {
        int statsMessageLength = app->parseOctreeStats(mutablePacket, sendingNode);
        wasStatsPacket = true;
        if (messageLength > statsMessageLength) {
            mutablePacket = mutablePacket.mid(statsMessageLength);
            
            // TODO: this does not look correct, the goal is to test the packet version for the piggyback, but
            //       this is testing the version and hash of the original packet
            if (!DependencyManager::get<NodeList>()->packetVersionAndHashMatch(packet)) {
                return; // bail since piggyback data doesn't match our versioning
            }
        } else {
            // Note... stats packets don't have sequence numbers, so we don't want to send those to trackIncomingVoxelPacket()
            return; // bail since no piggyback data
        }
    } // fall through to piggyback message
    
    voxelPacketType = packetTypeForPacket(mutablePacket);
    PacketVersion packetVersion = mutablePacket[1];
    PacketVersion expectedVersion = versionForPacketType(voxelPacketType);
    
    // check version of piggyback packet against expected version
    if (packetVersion != expectedVersion) {
        static QMultiMap<QUuid, PacketType> versionDebugSuppressMap;
        
        QUuid senderUUID = uuidFromPacketHeader(packet);
        if (!versionDebugSuppressMap.contains(senderUUID, voxelPacketType)) {
            qDebug() << "Packet version mismatch on" << voxelPacketType << "- Sender"
            << senderUUID << "sent" << (int)packetVersion << "but"
            << (int)expectedVersion << "expected.";
            
            emit packetVersionMismatch();

            versionDebugSuppressMap.insert(senderUUID, voxelPacketType);
        }
        return; // bail since piggyback version doesn't match
    }
    
    app->trackIncomingOctreePacket(mutablePacket, sendingNode, wasStatsPacket);

    if (sendingNode) {

        switch(voxelPacketType) {
            case PacketTypeEntityErase: {
                if (DependencyManager::get<SceneScriptingInterface>()->shouldRenderEntities()) {
                    app->_entities.processEraseMessage(mutablePacket, sendingNode);
                }
            } break;

            case PacketTypeEntityData: {
                if (DependencyManager::get<SceneScriptingInterface>()->shouldRenderEntities()) {
                    app->_entities.processDatagram(mutablePacket, sendingNode);
                }
            } break;

            case PacketTypeEnvironmentData: {
                app->_environment.parseData(*sendingNode->getActiveSocket(), mutablePacket);
            } break;

            default: {
                // nothing to do
            } break;
        }
    }
}
コード例 #28
0
void DatagramProcessor::processDatagrams() {

    if (_isShuttingDown) {
        return; // bail early... we're shutting down.
    }
    PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
                            "DatagramProcessor::processDatagrams()");


    HifiSockAddr senderSockAddr;

    static QByteArray incomingPacket;

    Application* application = Application::getInstance();
    auto nodeList = DependencyManager::get<NodeList>();

    while (DependencyManager::get<NodeList>()->getNodeSocket().hasPendingDatagrams()) {
        incomingPacket.resize(nodeList->getNodeSocket().pendingDatagramSize());
        nodeList->readDatagram(incomingPacket, senderSockAddr.getAddressPointer(), senderSockAddr.getPortPointer());

        _inPacketCount++;
        _inByteCount += 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(DependencyManager::get<AudioClient>().data(), "parseAudioStreamStatsPacket",
                                                  Qt::QueuedConnection,
                                                  Q_ARG(QByteArray, incomingPacket));
                    } else if (incomingType == PacketTypeAudioEnvironment) {
                        QMetaObject::invokeMethod(DependencyManager::get<AudioClient>().data(), "parseAudioEnvironmentData",
                                                  Qt::QueuedConnection,
                                                  Q_ARG(QByteArray, incomingPacket));
                    } else {
                        QMetaObject::invokeMethod(DependencyManager::get<AudioClient>().data(), "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());
                    }

                    break;
                }
                case PacketTypeEntityData:
                case PacketTypeEntityErase:
                case PacketTypeOctreeStats:
                case PacketTypeEnvironmentData: {
                    PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
                                            "Application::networkReceive()... _octreeProcessor.queueReceivedPacket()");
                    SharedNodePointer matchedNode = DependencyManager::get<NodeList>()->sendingNodeForPacket(incomingPacket);

                    if (matchedNode) {
                        // add this packet to our list of octree packets and process them on the octree data processing
                        application->_octreeProcessor.queueReceivedPacket(matchedNode, 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());

                        QMetaObject::invokeMethod(DependencyManager::get<AvatarManager>().data(), "processAvatarMixerDatagram",
                                                  Q_ARG(const QByteArray&, incomingPacket),
                                                  Q_ARG(const QWeakPointer<Node>&, avatarMixer));
                    }
                    break;
                }
                case PacketTypeDomainConnectionDenied: {
                    int headerSize = numBytesForPacketHeaderGivenPacketType(PacketTypeDomainConnectionDenied);
                    QDataStream packetStream(QByteArray(incomingPacket.constData() + headerSize,
                                                        incomingPacket.size() - headerSize));
                    QString reason;
                    packetStream >> reason;

                    // 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
                    qCDebug(interfaceapp) << "The domain-server denied a connection request: " << reason;
                    qCDebug(interfaceapp) << "You may need to re-log to generate a keypair so you can provide a username signature.";
                    application->domainConnectionDenied(reason);
                    AccountManager::getInstance().checkAndSignalForAccessToken();
                    break;
                }
                case PacketTypeNoisyMute:
                case PacketTypeMuteEnvironment: {
                    bool mute = !DependencyManager::get<AudioClient>()->isMuted();

                    if (incomingType == 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));
                        float distance = glm::distance(DependencyManager::get<AvatarManager>()->getMyAvatar()->getPosition(),
                                                 position);

                        mute = mute && (distance < radius);
                    }

                    if (mute) {
                        DependencyManager::get<AudioClient>()->toggleMute();
                        if (incomingType == PacketTypeMuteEnvironment) {
                            AudioScriptingInterface::getInstance().environmentMuted();
                        } else {
                            AudioScriptingInterface::getInstance().mutedByMixer();
                        }
                    }
                    break;
                }
                case PacketTypeEntityEditNack:
                    if (!Menu::getInstance()->isOptionChecked(MenuOption::DisableNackPackets)) {
                        application->_entityEditSender.processNackPacket(incomingPacket);
                    }
                    break;
                default:
                    nodeList->processNodeData(senderSockAddr, incomingPacket);
                    break;
            }
        }
    }
コード例 #29
0
ファイル: DataServer.cpp プロジェクト: MojoK/hifi
void DataServer::readPendingDatagrams() {
    QByteArray receivedPacket;
    HifiSockAddr senderSockAddr;
    
    while (_socket.hasPendingDatagrams()) {
        receivedPacket.resize(_socket.pendingDatagramSize());
        _socket.readDatagram(receivedPacket.data(), _socket.pendingDatagramSize(),
                             senderSockAddr.getAddressPointer(), senderSockAddr.getPortPointer());
        
        PacketType requestType = packetTypeForPacket(receivedPacket);
        
        if ((requestType == PacketTypeDataServerPut || requestType == PacketTypeDataServerGet) &&
            receivedPacket[numBytesArithmeticCodingFromBuffer(receivedPacket.data())] == versionForPacketType(requestType)) {
            
            QDataStream packetStream(receivedPacket);
            int numReceivedHeaderBytes = numBytesForPacketHeader(receivedPacket);
            packetStream.skipRawData(numReceivedHeaderBytes);
            
            // pull the sequence number used for this packet
            quint8 sequenceNumber = 0;
            
            packetStream >> sequenceNumber;
            
            // pull the UUID that we will need as part of the key
            QString userString;
            packetStream >> userString;
            QUuid parsedUUID(userString);
            
            if (parsedUUID.isNull()) {
                // we failed to parse a UUID, this means the user has sent us a username
                
                // ask redis for the UUID for this user
                redisReply* reply = (redisReply*) redisCommand(_redis, "GET user:%s", qPrintable(userString));
                
                if (reply->type == REDIS_REPLY_STRING) {
                    parsedUUID = QUuid(QString(reply->str));
                }
                
                if (!parsedUUID.isNull()) {
                    qDebug() << "Found UUID" << parsedUUID << "for username" << userString;
                } else {
                    qDebug() << "Failed UUID lookup for username" << userString;
                }
                
                freeReplyObject(reply);
                reply = NULL;
            }
            
            if (!parsedUUID.isNull()) {
                if (requestType == PacketTypeDataServerPut) {
                    
                    // pull the key and value that specifies the data the user is putting/getting
                    QString dataKey, dataValue;
                    
                    packetStream >> dataKey >> dataValue;
                    
                    qDebug("Sending command to redis: SET uuid:%s:%s %s",
                           qPrintable(uuidStringWithoutCurlyBraces(parsedUUID)),
                           qPrintable(dataKey), qPrintable(dataValue));
                    
                    redisReply* reply = (redisReply*) redisCommand(_redis, "SET uuid:%s:%s %s",
                                                                   qPrintable(uuidStringWithoutCurlyBraces(parsedUUID)),
                                                                   qPrintable(dataKey), qPrintable(dataValue));
                    
                    if (reply->type == REDIS_REPLY_STATUS && strcmp("OK", reply->str) == 0) {
                        // if redis stored the value successfully reply back with a confirm
                        // which is a reply packet with the sequence number
                        QByteArray replyPacket = byteArrayWithPopluatedHeader(PacketTypeDataServerConfirm, _uuid);
                        
                        replyPacket.append(sequenceNumber);
                        
                        _socket.writeDatagram(replyPacket, senderSockAddr.getAddress(), senderSockAddr.getPort());
                    }
                    
                    freeReplyObject(reply);
                } else {
                    // setup a send packet with the returned data
                    // leverage the packetData sent by overwriting and appending
                    QByteArray sendPacket = byteArrayWithPopluatedHeader(PacketTypeDataServerSend, _uuid);
                    QDataStream sendPacketStream(&sendPacket, QIODevice::Append);
                    
                    sendPacketStream << sequenceNumber;
                    
                    // pull the key list that specifies the data the user is putting/getting
                    QString keyListString;
                    packetStream >> keyListString;
                    
                    if (keyListString != "uuid") {
                        
                        // copy the parsed UUID
                        sendPacketStream << uuidStringWithoutCurlyBraces(parsedUUID);
                        
                        const char MULTI_KEY_VALUE_SEPARATOR = '|';
                        
                        // append the keyListString back to the sendPacket
                        sendPacketStream << keyListString;
                        
                        QStringList keyList = keyListString.split(MULTI_KEY_VALUE_SEPARATOR);
                        QStringList valueList;
                        
                        foreach (const QString& dataKey, keyList) {
                            qDebug("Sending command to redis: GET uuid:%s:%s",
                                   qPrintable(uuidStringWithoutCurlyBraces(parsedUUID)),
                                   qPrintable(dataKey));
                            redisReply* reply = (redisReply*) redisCommand(_redis, "GET uuid:%s:%s",
                                                                           qPrintable(uuidStringWithoutCurlyBraces(parsedUUID)),
                                                                           qPrintable(dataKey));
                            
                            if (reply->len) {
                                // copy the value that redis returned
                                valueList << QString(reply->str);
                            } else {
                                // didn't find a value - insert a space
                                valueList << QChar(' ');
                            }
                            
                            freeReplyObject(reply);
                        }
                        
                        // append the value QStringList using the right separator
                        sendPacketStream << valueList.join(MULTI_KEY_VALUE_SEPARATOR);
                    } else {
コード例 #30
0
ファイル: DatagramProcessor.cpp プロジェクト: RyanDowne/hifi
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;
            }
        }
    }