overte/libraries/networking/src/PacketReceiver.cpp
2015-07-08 11:54:50 -07:00

183 lines
8.3 KiB
C++

//
// PacketReceiver.cpp
// interface/src
//
// Created by Stephen Birarda on 1/23/2014.
// Update by Ryan Huffman on 7/8/2015.
// Copyright 2014 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include <QtCore/QWeakPointer>
#include <AccountManager.h>
#include <PerfStat.h>
#include "Application.h"
#include "avatar/AvatarManager.h"
#include "AudioClient.h"
#include "Menu.h"
#include "InterfaceLogging.h"
#include "PacketReceiver.h"
PacketReceiver::PacketReceiver(QObject* parent) :
QObject(parent),
_packetListenerMap()
{
}
void PacketReceiver::registerPacketListener(PacketType::Value type, QObject* object, QString methodName) {
packetListenerLock.lock();
if (packetListenerMap.contains(type)) {
qDebug() << "Warning: Registering a packet listener for packet type " << type
<< " that will remove a previously registered listener";
}
packetListenerMap[type] = QPair<QObject*, QString>(object, methodName);
packetListenerLock.unlock();
}
void PacketReceiver::processDatagrams() {
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
"PacketReceiver::processDatagrams()");
if (_isShuttingDown) {
return; // bail early... we're shutting down.
}
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::Value incomingType = packetTypeForPacket(incomingPacket);
// only process this packet if we have a match on the packet version
switch (incomingType) {
case PacketType::AudioEnvironment:
case PacketType::AudioStreamStats:
case PacketType::MixedAudio:
case PacketType::SilentAudioFrame: {
if (incomingType == PacketType::AudioStreamStats) {
QMetaObject::invokeMethod(DependencyManager::get<AudioClient>().data(), "parseAudioStreamStatsPacket",
Qt::QueuedConnection,
Q_ARG(QByteArray, incomingPacket));
} else if (incomingType == PacketType::AudioEnvironment) {
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 PacketType::EntityData:
case PacketType::EntityErase:
case PacketType::OctreeStats:
case PacketType::EnvironmentData: {
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 PacketType::BulkAvatarData:
case PacketType::KillAvatar:
case PacketType::AvatarIdentity:
case PacketType::AvatarBillboard: {
// 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 PacketType::NoisyMute:
case PacketType::MuteEnvironment: {
bool mute = !DependencyManager::get<AudioClient>()->isMuted();
if (incomingType == PacketType::MuteEnvironment) {
glm::vec3 position;
float radius;
int headerSize = numBytesForPacketHeaderGivenPacketType(PacketType::MuteEnvironment);
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 == PacketType::MuteEnvironment) {
AudioScriptingInterface::getInstance().environmentMuted();
} else {
AudioScriptingInterface::getInstance().mutedByMixer();
}
}
break;
}
case PacketType::EntityEditNack:
if (!Menu::getInstance()->isOptionChecked(MenuOption::DisableNackPackets)) {
application->_entityEditSender.processNackPacket(incomingPacket);
}
break;
default:
//nodeList->processNodeData(senderSockAddr, incomingPacket);
packetListenerLock.lock();
auto& listener = packetListenerMap[incomingType];
packetListenerLock.unlock();
if (packetListenerMap.contains(incomingType)) {
auto& listener = packetListenerMap[incomingType];
NLPacket packet;
bool success = QMetaObject::invokeMethod(listener.first, listener.second,
Q_ARG(std::unique_ptr<NLPacket>, packet),
Q_ARG(HifiSockAddr, senderSockAddr));
if (!success) {
qDebug() << "Error sending packet " << incomingType << " to listener: " << listener.first.name() << "::" << listener.second;
}
} else {
QDebug() << "No listener found for packet type: " << incomingType;
}
break;
}
}
}
}