示例#1
0
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);
    }
}
示例#2
0
void NodeList::startNodeHolePunch(const SharedNodePointer& node) {
    // connect to the correct signal on this node so we know when to ping it
    connect(node.data(), &Node::pingTimerTimeout, this, &NodeList::handleNodePingTimeout);

    // start the ping timer for this node
    node->startPingTimer();

    // ping this node immediately
    pingPunchForInactiveNode(node);
}
示例#3
0
int LimitedNodeList::updateNodeWithDataFromPacket(const SharedNodePointer& matchingNode, const QByteArray &packet) {
    QMutexLocker locker(&matchingNode->getMutex());
    
    matchingNode->setLastHeardMicrostamp(usecTimestampNow());
    matchingNode->recordBytesReceived(packet.size());
    
    if (!matchingNode->getLinkedData() && linkedDataCreateCallback) {
        linkedDataCreateCallback(matchingNode.data());
    }
    
    QMutexLocker linkedDataLocker(&matchingNode->getLinkedData()->getMutex());
    
    return matchingNode->getLinkedData()->parseData(packet);
}
示例#4
0
int LimitedNodeList::updateNodeWithDataFromPacket(QSharedPointer<NLPacket> packet, SharedNodePointer sendingNode) {
    QMutexLocker locker(&sendingNode->getMutex());

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

    if (linkedData) {
        QMutexLocker linkedDataLocker(&linkedData->getMutex());
        return linkedData->parseData(*packet);
    }
    
    return 0;
}
示例#5
0
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;
}
示例#6
0
void AvatarMixerClientData::ignoreOther(SharedNodePointer self, SharedNodePointer other) {
    ignoreOther(self.data(), other.data());
}
示例#7
0
void AudioInjector::injectAudio() {

    QByteArray soundByteArray = _sound->getByteArray();

    // make sure we actually have samples downloaded to inject
    if (soundByteArray.size()) {
        // give our sample byte array to the local audio interface, if we have it, so it can be handled locally
        if (_options.getLoopbackAudioInterface()) {
            // assume that localAudioInterface could be on a separate thread, use Qt::AutoConnection to handle properly
            QMetaObject::invokeMethod(_options.getLoopbackAudioInterface(), "handleAudioByteArray",
                                      Qt::AutoConnection,
                                      Q_ARG(QByteArray, soundByteArray));

        }

        NodeList* nodeList = NodeList::getInstance();

        // setup the packet for injected audio
        QByteArray injectAudioPacket = byteArrayWithPopluatedHeader(PacketTypeInjectAudio);
        QDataStream packetStream(&injectAudioPacket, QIODevice::Append);

        packetStream << QUuid::createUuid();

        // pack the flag for loopback
        uchar loopbackFlag = (uchar) (_options.getLoopbackAudioInterface() == NULL);
        packetStream << loopbackFlag;

        // pack the position for injected audio
        packetStream.writeRawData(reinterpret_cast<const char*>(&_options.getPosition()), sizeof(_options.getPosition()));

        // pack our orientation for injected audio
        packetStream.writeRawData(reinterpret_cast<const char*>(&_options.getOrientation()), sizeof(_options.getOrientation()));

        // pack zero for radius
        float radius = 0;
        packetStream << radius;

        // pack 255 for attenuation byte
        quint8 volume = MAX_INJECTOR_VOLUME * _options.getVolume();
        packetStream << volume;

        timeval startTime = {};
        gettimeofday(&startTime, NULL);
        int nextFrame = 0;

        int currentSendPosition = 0;

        int numPreAudioDataBytes = injectAudioPacket.size();

        // loop to send off our audio in NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL byte chunks
        while (currentSendPosition < soundByteArray.size()) {

            int bytesToCopy = std::min(NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL,
                                       soundByteArray.size() - currentSendPosition);

            // resize the QByteArray to the right size
            injectAudioPacket.resize(numPreAudioDataBytes + bytesToCopy);

            // copy the next NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL bytes to the packet
            memcpy(injectAudioPacket.data() + numPreAudioDataBytes, soundByteArray.data() + currentSendPosition, bytesToCopy);

            // grab our audio mixer from the NodeList, if it exists
            SharedNodePointer audioMixer = nodeList->soloNodeOfType(NodeType::AudioMixer);

            if (audioMixer && nodeList->getNodeActiveSocketOrPing(audioMixer.data())) {
                // send off this audio packet
                nodeList->getNodeSocket().writeDatagram(injectAudioPacket,
                                                        audioMixer->getActiveSocket()->getAddress(),
                                                        audioMixer->getActiveSocket()->getPort());
            }

            currentSendPosition += bytesToCopy;

            // send two packets before the first sleep so the mixer can start playback right away

            if (currentSendPosition != bytesToCopy && currentSendPosition < soundByteArray.size()) {
                // not the first packet and not done
                // sleep for the appropriate time
                int usecToSleep = usecTimestamp(&startTime) + (++nextFrame * BUFFER_SEND_INTERVAL_USECS) - usecTimestampNow();

                if (usecToSleep > 0) {
                    usleep(usecToSleep);
                }
            }
        }
    }

    emit finished();
}