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); } }
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); }
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); }
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; }
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; }
void AvatarMixerClientData::ignoreOther(SharedNodePointer self, SharedNodePointer other) { ignoreOther(self.data(), other.data()); }
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(); }