mirror of
https://github.com/lubosz/overte.git
synced 2025-04-23 20:54:25 +02:00
your agents are now nodes
This commit is contained in:
parent
00fa688aba
commit
36c6912de8
42 changed files with 1519 additions and 1519 deletions
|
@ -11,8 +11,8 @@
|
|||
#include <cstring>
|
||||
#include <cstdio>
|
||||
#include <OctalCode.h>
|
||||
#include <AgentList.h>
|
||||
#include <AgentTypes.h>
|
||||
#include <NodeList.h>
|
||||
#include <NodeTypes.h>
|
||||
#include <EnvironmentData.h>
|
||||
#include <VoxelTree.h>
|
||||
#include <SharedUtil.h>
|
||||
|
@ -59,7 +59,7 @@ static void sendVoxelEditMessage(PACKET_HEADER header, VoxelDetail& detail) {
|
|||
printf("sending packet of size=%d\n",sizeOut);
|
||||
}
|
||||
|
||||
AgentList::getInstance()->broadcastToAgents(bufferOut, sizeOut, &AGENT_TYPE_VOXEL_SERVER, 1);
|
||||
NodeList::getInstance()->broadcastToNodes(bufferOut, sizeOut, &NODE_TYPE_VOXEL_SERVER, 1);
|
||||
delete[] bufferOut;
|
||||
}
|
||||
}
|
||||
|
@ -168,7 +168,7 @@ static void renderMovingBug() {
|
|||
if (::shouldShowPacketsPerSecond) {
|
||||
printf("sending packet of size=%d\n", sizeOut);
|
||||
}
|
||||
AgentList::getInstance()->broadcastToAgents(bufferOut, sizeOut, &AGENT_TYPE_VOXEL_SERVER, 1);
|
||||
NodeList::getInstance()->broadcastToNodes(bufferOut, sizeOut, &NODE_TYPE_VOXEL_SERVER, 1);
|
||||
delete[] bufferOut;
|
||||
}
|
||||
|
||||
|
@ -238,7 +238,7 @@ static void renderMovingBug() {
|
|||
if (::shouldShowPacketsPerSecond) {
|
||||
printf("sending packet of size=%d\n", sizeOut);
|
||||
}
|
||||
AgentList::getInstance()->broadcastToAgents(bufferOut, sizeOut, &AGENT_TYPE_VOXEL_SERVER, 1);
|
||||
NodeList::getInstance()->broadcastToNodes(bufferOut, sizeOut, &NODE_TYPE_VOXEL_SERVER, 1);
|
||||
delete[] bufferOut;
|
||||
}
|
||||
}
|
||||
|
@ -344,7 +344,7 @@ static void sendBlinkingStringOfLights() {
|
|||
if (::shouldShowPacketsPerSecond) {
|
||||
printf("sending packet of size=%d\n",sizeOut);
|
||||
}
|
||||
AgentList::getInstance()->broadcastToAgents(bufferOut, sizeOut, &AGENT_TYPE_VOXEL_SERVER, 1);
|
||||
NodeList::getInstance()->broadcastToNodes(bufferOut, sizeOut, &NODE_TYPE_VOXEL_SERVER, 1);
|
||||
delete[] bufferOut;
|
||||
}
|
||||
|
||||
|
@ -386,7 +386,7 @@ static void sendBlinkingStringOfLights() {
|
|||
if (::shouldShowPacketsPerSecond) {
|
||||
printf("sending packet of size=%d\n",sizeOut);
|
||||
}
|
||||
AgentList::getInstance()->broadcastToAgents(bufferOut, sizeOut, &AGENT_TYPE_VOXEL_SERVER, 1);
|
||||
NodeList::getInstance()->broadcastToNodes(bufferOut, sizeOut, &NODE_TYPE_VOXEL_SERVER, 1);
|
||||
delete[] bufferOut;
|
||||
}
|
||||
}
|
||||
|
@ -509,7 +509,7 @@ void sendDanceFloor() {
|
|||
if (::shouldShowPacketsPerSecond) {
|
||||
printf("sending packet of size=%d\n", sizeOut);
|
||||
}
|
||||
AgentList::getInstance()->broadcastToAgents(bufferOut, sizeOut, &AGENT_TYPE_VOXEL_SERVER, 1);
|
||||
NodeList::getInstance()->broadcastToNodes(bufferOut, sizeOut, &NODE_TYPE_VOXEL_SERVER, 1);
|
||||
delete[] bufferOut;
|
||||
}
|
||||
}
|
||||
|
@ -606,7 +606,7 @@ static void sendBillboard() {
|
|||
if (::shouldShowPacketsPerSecond) {
|
||||
printf("sending packet of size=%d\n", sizeOut);
|
||||
}
|
||||
AgentList::getInstance()->broadcastToAgents(bufferOut, sizeOut, &AGENT_TYPE_VOXEL_SERVER, 1);
|
||||
NodeList::getInstance()->broadcastToNodes(bufferOut, sizeOut, &NODE_TYPE_VOXEL_SERVER, 1);
|
||||
delete[] bufferOut;
|
||||
}
|
||||
}
|
||||
|
@ -667,7 +667,7 @@ int main(int argc, const char * argv[])
|
|||
{
|
||||
::start = usecTimestampNow();
|
||||
|
||||
AgentList* agentList = AgentList::createInstance(AGENT_TYPE_ANIMATION_SERVER, ANIMATION_LISTEN_PORT);
|
||||
NodeList* nodeList = NodeList::createInstance(NODE_TYPE_ANIMATION_SERVER, ANIMATION_LISTEN_PORT);
|
||||
setvbuf(stdout, NULL, _IOLBF, 0);
|
||||
|
||||
// Handle Local Domain testing with the --local command line
|
||||
|
@ -699,33 +699,33 @@ int main(int argc, const char * argv[])
|
|||
sprintf(DOMAIN_IP,"%d.%d.%d.%d", (ip & 0xFF), ((ip >> 8) & 0xFF),((ip >> 16) & 0xFF), ((ip >> 24) & 0xFF));
|
||||
}
|
||||
|
||||
agentList->linkedDataCreateCallback = NULL; // do we need a callback?
|
||||
agentList->startSilentAgentRemovalThread();
|
||||
nodeList->linkedDataCreateCallback = NULL; // do we need a callback?
|
||||
nodeList->startSilentNodeRemovalThread();
|
||||
|
||||
srand((unsigned)time(0));
|
||||
|
||||
pthread_t animateVoxelThread;
|
||||
pthread_create(&animateVoxelThread, NULL, animateVoxels, NULL);
|
||||
|
||||
sockaddr agentPublicAddress;
|
||||
sockaddr nodePublicAddress;
|
||||
|
||||
unsigned char* packetData = new unsigned char[MAX_PACKET_SIZE];
|
||||
ssize_t receivedBytes;
|
||||
|
||||
timeval lastDomainServerCheckIn = {};
|
||||
AgentList::getInstance()->setAgentTypesOfInterest(&AGENT_TYPE_VOXEL_SERVER, 1);
|
||||
NodeList::getInstance()->setNodeTypesOfInterest(&NODE_TYPE_VOXEL_SERVER, 1);
|
||||
|
||||
// loop to send to agents requesting data
|
||||
// loop to send to nodes requesting data
|
||||
while (true) {
|
||||
// send a check in packet to the domain server if DOMAIN_SERVER_CHECK_IN_USECS has elapsed
|
||||
if (usecTimestampNow() - usecTimestamp(&lastDomainServerCheckIn) >= DOMAIN_SERVER_CHECK_IN_USECS) {
|
||||
gettimeofday(&lastDomainServerCheckIn, NULL);
|
||||
AgentList::getInstance()->sendDomainServerCheckIn();
|
||||
NodeList::getInstance()->sendDomainServerCheckIn();
|
||||
}
|
||||
|
||||
// Agents sending messages to us...
|
||||
if (agentList->getAgentSocket()->receive(&agentPublicAddress, packetData, &receivedBytes)) {
|
||||
AgentList::getInstance()->processAgentData(&agentPublicAddress, packetData, receivedBytes);
|
||||
// Nodes sending messages to us...
|
||||
if (nodeList->getNodeSocket()->receive(&nodePublicAddress, packetData, &receivedBytes)) {
|
||||
NodeList::getInstance()->processNodeData(&nodePublicAddress, packetData, receivedBytes);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -12,18 +12,18 @@
|
|||
|
||||
AvatarAudioRingBuffer::AvatarAudioRingBuffer() :
|
||||
_twoPoles(),
|
||||
_shouldLoopbackForAgent(false) {
|
||||
_shouldLoopbackForNode(false) {
|
||||
|
||||
}
|
||||
|
||||
AvatarAudioRingBuffer::~AvatarAudioRingBuffer() {
|
||||
// enumerate the freeVerbs map and delete the FreeVerb objects
|
||||
for (TwoPoleAgentMap::iterator poleIterator = _twoPoles.begin(); poleIterator != _twoPoles.end(); poleIterator++) {
|
||||
for (TwoPoleNodeMap::iterator poleIterator = _twoPoles.begin(); poleIterator != _twoPoles.end(); poleIterator++) {
|
||||
delete poleIterator->second;
|
||||
}
|
||||
}
|
||||
|
||||
int AvatarAudioRingBuffer::parseData(unsigned char* sourceBuffer, int numBytes) {
|
||||
_shouldLoopbackForAgent = (sourceBuffer[0] == PACKET_HEADER_MICROPHONE_AUDIO_WITH_ECHO);
|
||||
_shouldLoopbackForNode = (sourceBuffer[0] == PACKET_HEADER_MICROPHONE_AUDIO_WITH_ECHO);
|
||||
return PositionalAudioRingBuffer::parseData(sourceBuffer, numBytes);
|
||||
}
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
#include "PositionalAudioRingBuffer.h"
|
||||
|
||||
typedef std::map<uint16_t, stk::TwoPole*> TwoPoleAgentMap;
|
||||
typedef std::map<uint16_t, stk::TwoPole*> TwoPoleNodeMap;
|
||||
|
||||
class AvatarAudioRingBuffer : public PositionalAudioRingBuffer {
|
||||
public:
|
||||
|
@ -23,16 +23,16 @@ public:
|
|||
|
||||
int parseData(unsigned char* sourceBuffer, int numBytes);
|
||||
|
||||
TwoPoleAgentMap& getTwoPoles() { return _twoPoles; }
|
||||
TwoPoleNodeMap& getTwoPoles() { return _twoPoles; }
|
||||
|
||||
bool shouldLoopbackForAgent() const { return _shouldLoopbackForAgent; }
|
||||
bool shouldLoopbackForNode() const { return _shouldLoopbackForNode; }
|
||||
private:
|
||||
// disallow copying of AvatarAudioRingBuffer objects
|
||||
AvatarAudioRingBuffer(const AvatarAudioRingBuffer&);
|
||||
AvatarAudioRingBuffer& operator= (const AvatarAudioRingBuffer&);
|
||||
|
||||
TwoPoleAgentMap _twoPoles;
|
||||
bool _shouldLoopbackForAgent;
|
||||
TwoPoleNodeMap _twoPoles;
|
||||
bool _shouldLoopbackForNode;
|
||||
};
|
||||
|
||||
#endif /* defined(__hifi__AvatarAudioRingBuffer__) */
|
||||
|
|
|
@ -38,7 +38,7 @@ int PositionalAudioRingBuffer::parsePositionalData(unsigned char* sourceBuffer,
|
|||
memcpy(&_orientation, currentBuffer, sizeof(_orientation));
|
||||
currentBuffer += sizeof(_orientation);
|
||||
|
||||
// if this agent sent us a NaN for first float in orientation then don't consider this good audio and bail
|
||||
// if this node sent us a NaN for first float in orientation then don't consider this good audio and bail
|
||||
if (std::isnan(_orientation.x)) {
|
||||
_endOfLastWrite = _nextOutput = _buffer;
|
||||
_isStarted = false;
|
||||
|
|
|
@ -19,9 +19,9 @@
|
|||
|
||||
#include <glm/gtx/norm.hpp>
|
||||
#include <glm/gtx/vector_angle.hpp>
|
||||
#include <AgentList.h>
|
||||
#include <Agent.h>
|
||||
#include <AgentTypes.h>
|
||||
#include <NodeList.h>
|
||||
#include <Node.h>
|
||||
#include <NodeTypes.h>
|
||||
#include <SharedUtil.h>
|
||||
#include <StdDev.h>
|
||||
#include <Logstash.h>
|
||||
|
@ -61,12 +61,12 @@ void plateauAdditionOfSamples(int16_t &mixSample, int16_t sampleToAdd) {
|
|||
mixSample = normalizedSample;
|
||||
}
|
||||
|
||||
void attachNewBufferToAgent(Agent *newAgent) {
|
||||
if (!newAgent->getLinkedData()) {
|
||||
if (newAgent->getType() == AGENT_TYPE_AVATAR) {
|
||||
newAgent->setLinkedData(new AvatarAudioRingBuffer());
|
||||
void attachNewBufferToNode(Node *newNode) {
|
||||
if (!newNode->getLinkedData()) {
|
||||
if (newNode->getType() == NODE_TYPE_AGENT) {
|
||||
newNode->setLinkedData(new AvatarAudioRingBuffer());
|
||||
} else {
|
||||
newAgent->setLinkedData(new InjectedAudioRingBuffer());
|
||||
newNode->setLinkedData(new InjectedAudioRingBuffer());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -85,20 +85,20 @@ int main(int argc, const char* argv[]) {
|
|||
sprintf(DOMAIN_IP,"%d.%d.%d.%d", (ip & 0xFF), ((ip >> 8) & 0xFF),((ip >> 16) & 0xFF), ((ip >> 24) & 0xFF));
|
||||
}
|
||||
|
||||
AgentList* agentList = AgentList::createInstance(AGENT_TYPE_AUDIO_MIXER, MIXER_LISTEN_PORT);
|
||||
NodeList* nodeList = NodeList::createInstance(NODE_TYPE_AUDIO_MIXER, MIXER_LISTEN_PORT);
|
||||
|
||||
ssize_t receivedBytes = 0;
|
||||
|
||||
agentList->linkedDataCreateCallback = attachNewBufferToAgent;
|
||||
nodeList->linkedDataCreateCallback = attachNewBufferToNode;
|
||||
|
||||
agentList->startSilentAgentRemovalThread();
|
||||
nodeList->startSilentNodeRemovalThread();
|
||||
|
||||
unsigned char* packetData = new unsigned char[MAX_PACKET_SIZE];
|
||||
|
||||
sockaddr* agentAddress = new sockaddr;
|
||||
sockaddr* nodeAddress = new sockaddr;
|
||||
|
||||
// make sure our agent socket is non-blocking
|
||||
agentList->getAgentSocket()->setBlocking(false);
|
||||
// make sure our node socket is non-blocking
|
||||
nodeList->getNodeSocket()->setBlocking(false);
|
||||
|
||||
int nextFrame = 0;
|
||||
timeval startTime;
|
||||
|
@ -131,7 +131,7 @@ int main(int argc, const char* argv[]) {
|
|||
// send a check in packet to the domain server if DOMAIN_SERVER_CHECK_IN_USECS has elapsed
|
||||
if (usecTimestampNow() - usecTimestamp(&lastDomainServerCheckIn) >= DOMAIN_SERVER_CHECK_IN_USECS) {
|
||||
gettimeofday(&lastDomainServerCheckIn, NULL);
|
||||
AgentList::getInstance()->sendDomainServerCheckIn();
|
||||
NodeList::getInstance()->sendDomainServerCheckIn();
|
||||
|
||||
if (Logstash::shouldSendStats() && numStatCollections > 0) {
|
||||
// if we should be sending stats to Logstash send the appropriate average now
|
||||
|
@ -145,8 +145,8 @@ int main(int argc, const char* argv[]) {
|
|||
}
|
||||
}
|
||||
|
||||
for (AgentList::iterator agent = agentList->begin(); agent != agentList->end(); agent++) {
|
||||
PositionalAudioRingBuffer* positionalRingBuffer = (PositionalAudioRingBuffer*) agent->getLinkedData();
|
||||
for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
|
||||
PositionalAudioRingBuffer* positionalRingBuffer = (PositionalAudioRingBuffer*) node->getLinkedData();
|
||||
|
||||
if (positionalRingBuffer && positionalRingBuffer->shouldBeAddedToMix(JITTER_BUFFER_SAMPLES)) {
|
||||
// this is a ring buffer that is ready to go
|
||||
|
@ -155,40 +155,40 @@ int main(int argc, const char* argv[]) {
|
|||
}
|
||||
}
|
||||
|
||||
for (AgentList::iterator agent = agentList->begin(); agent != agentList->end(); agent++) {
|
||||
for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
|
||||
|
||||
const int PHASE_DELAY_AT_90 = 20;
|
||||
|
||||
if (agent->getType() == AGENT_TYPE_AVATAR) {
|
||||
AvatarAudioRingBuffer* agentRingBuffer = (AvatarAudioRingBuffer*) agent->getLinkedData();
|
||||
if (node->getType() == NODE_TYPE_AGENT) {
|
||||
AvatarAudioRingBuffer* nodeRingBuffer = (AvatarAudioRingBuffer*) node->getLinkedData();
|
||||
|
||||
// zero out the client mix for this agent
|
||||
// zero out the client mix for this node
|
||||
memset(clientSamples, 0, sizeof(clientSamples));
|
||||
|
||||
for (AgentList::iterator otherAgent = agentList->begin(); otherAgent != agentList->end(); otherAgent++) {
|
||||
if (((PositionalAudioRingBuffer*) otherAgent->getLinkedData())->willBeAddedToMix()
|
||||
&& (otherAgent != agent || (otherAgent == agent && agentRingBuffer->shouldLoopbackForAgent()))) {
|
||||
for (NodeList::iterator otherNode = nodeList->begin(); otherNode != nodeList->end(); otherNode++) {
|
||||
if (((PositionalAudioRingBuffer*) otherNode->getLinkedData())->willBeAddedToMix()
|
||||
&& (otherNode != node || (otherNode == node && nodeRingBuffer->shouldLoopbackForNode()))) {
|
||||
|
||||
PositionalAudioRingBuffer* otherAgentBuffer = (PositionalAudioRingBuffer*) otherAgent->getLinkedData();
|
||||
PositionalAudioRingBuffer* otherNodeBuffer = (PositionalAudioRingBuffer*) otherNode->getLinkedData();
|
||||
|
||||
float bearingRelativeAngleToSource = 0.0f;
|
||||
float attenuationCoefficient = 1.0f;
|
||||
int numSamplesDelay = 0;
|
||||
float weakChannelAmplitudeRatio = 1.0f;
|
||||
|
||||
stk::TwoPole* otherAgentTwoPole = NULL;
|
||||
stk::TwoPole* otherNodeTwoPole = NULL;
|
||||
|
||||
if (otherAgent != agent) {
|
||||
if (otherNode != node) {
|
||||
|
||||
glm::vec3 listenerPosition = agentRingBuffer->getPosition();
|
||||
glm::vec3 relativePosition = otherAgentBuffer->getPosition() - agentRingBuffer->getPosition();
|
||||
glm::quat inverseOrientation = glm::inverse(agentRingBuffer->getOrientation());
|
||||
glm::vec3 listenerPosition = nodeRingBuffer->getPosition();
|
||||
glm::vec3 relativePosition = otherNodeBuffer->getPosition() - nodeRingBuffer->getPosition();
|
||||
glm::quat inverseOrientation = glm::inverse(nodeRingBuffer->getOrientation());
|
||||
|
||||
float distanceSquareToSource = glm::dot(relativePosition, relativePosition);
|
||||
float radius = 0.0f;
|
||||
|
||||
if (otherAgent->getType() == AGENT_TYPE_AUDIO_INJECTOR) {
|
||||
InjectedAudioRingBuffer* injectedBuffer = (InjectedAudioRingBuffer*) otherAgentBuffer;
|
||||
if (otherNode->getType() == NODE_TYPE_AUDIO_INJECTOR) {
|
||||
InjectedAudioRingBuffer* injectedBuffer = (InjectedAudioRingBuffer*) otherNodeBuffer;
|
||||
radius = injectedBuffer->getRadius();
|
||||
attenuationCoefficient *= injectedBuffer->getAttenuationRatio();
|
||||
}
|
||||
|
@ -200,13 +200,13 @@ int main(int argc, const char* argv[]) {
|
|||
// this is a spherical source - the distance used for the coefficient
|
||||
// needs to be the closest point on the boundary to the source
|
||||
|
||||
// ovveride the distance to the agent with the distance to the point on the
|
||||
// ovveride the distance to the node with the distance to the point on the
|
||||
// boundary of the sphere
|
||||
distanceSquareToSource -= (radius * radius);
|
||||
|
||||
} else {
|
||||
// calculate the angle delivery for off-axis attenuation
|
||||
glm::vec3 rotatedListenerPosition = glm::inverse(otherAgentBuffer->getOrientation())
|
||||
glm::vec3 rotatedListenerPosition = glm::inverse(otherNodeBuffer->getOrientation())
|
||||
* relativePosition;
|
||||
|
||||
float angleOfDelivery = glm::angle(glm::vec3(0.0f, 0.0f, -1.0f),
|
||||
|
@ -229,7 +229,7 @@ int main(int argc, const char* argv[]) {
|
|||
const float DISTANCE_LOG_BASE = 2.5f;
|
||||
const float DISTANCE_SCALE_LOG = logf(DISTANCE_SCALE) / logf(DISTANCE_LOG_BASE);
|
||||
|
||||
// calculate the distance coefficient using the distance to this agent
|
||||
// calculate the distance coefficient using the distance to this node
|
||||
float distanceCoefficient = powf(GEOMETRIC_AMPLITUDE_SCALAR,
|
||||
DISTANCE_SCALE_LOG +
|
||||
(0.5f * logf(distanceSquareToSource) / logf(DISTANCE_LOG_BASE)) - 1);
|
||||
|
@ -255,28 +255,28 @@ int main(int argc, const char* argv[]) {
|
|||
weakChannelAmplitudeRatio = 1 - (PHASE_AMPLITUDE_RATIO_AT_90 * sinRatio);
|
||||
|
||||
// grab the TwoPole object for this source, add it if it doesn't exist
|
||||
TwoPoleAgentMap& agentTwoPoles = agentRingBuffer->getTwoPoles();
|
||||
TwoPoleAgentMap::iterator twoPoleIterator = agentTwoPoles.find(otherAgent->getAgentID());
|
||||
TwoPoleNodeMap& nodeTwoPoles = nodeRingBuffer->getTwoPoles();
|
||||
TwoPoleNodeMap::iterator twoPoleIterator = nodeTwoPoles.find(otherNode->getNodeID());
|
||||
|
||||
if (twoPoleIterator == agentTwoPoles.end()) {
|
||||
if (twoPoleIterator == nodeTwoPoles.end()) {
|
||||
// setup the freeVerb effect for this source for this client
|
||||
otherAgentTwoPole = agentTwoPoles[otherAgent->getAgentID()] = new stk::TwoPole;
|
||||
otherNodeTwoPole = nodeTwoPoles[otherNode->getNodeID()] = new stk::TwoPole;
|
||||
} else {
|
||||
otherAgentTwoPole = twoPoleIterator->second;
|
||||
otherNodeTwoPole = twoPoleIterator->second;
|
||||
}
|
||||
|
||||
// calculate the reasonance for this TwoPole based on angle to source
|
||||
float TWO_POLE_CUT_OFF_FREQUENCY = 800.0f;
|
||||
float TWO_POLE_MAX_FILTER_STRENGTH = 0.4f;
|
||||
|
||||
otherAgentTwoPole->setResonance(TWO_POLE_CUT_OFF_FREQUENCY,
|
||||
otherNodeTwoPole->setResonance(TWO_POLE_CUT_OFF_FREQUENCY,
|
||||
TWO_POLE_MAX_FILTER_STRENGTH
|
||||
* fabsf(bearingRelativeAngleToSource) / 180.0f,
|
||||
true);
|
||||
}
|
||||
}
|
||||
|
||||
int16_t* sourceBuffer = otherAgentBuffer->getNextOutput();
|
||||
int16_t* sourceBuffer = otherNodeBuffer->getNextOutput();
|
||||
|
||||
int16_t* goodChannel = (bearingRelativeAngleToSource > 0.0f)
|
||||
? clientSamples
|
||||
|
@ -285,9 +285,9 @@ int main(int argc, const char* argv[]) {
|
|||
? clientSamples + BUFFER_LENGTH_SAMPLES_PER_CHANNEL
|
||||
: clientSamples;
|
||||
|
||||
int16_t* delaySamplePointer = otherAgentBuffer->getNextOutput() == otherAgentBuffer->getBuffer()
|
||||
? otherAgentBuffer->getBuffer() + RING_BUFFER_LENGTH_SAMPLES - numSamplesDelay
|
||||
: otherAgentBuffer->getNextOutput() - numSamplesDelay;
|
||||
int16_t* delaySamplePointer = otherNodeBuffer->getNextOutput() == otherNodeBuffer->getBuffer()
|
||||
? otherNodeBuffer->getBuffer() + RING_BUFFER_LENGTH_SAMPLES - numSamplesDelay
|
||||
: otherNodeBuffer->getNextOutput() - numSamplesDelay;
|
||||
|
||||
for (int s = 0; s < BUFFER_LENGTH_SAMPLES_PER_CHANNEL; s++) {
|
||||
// load up the stkFrameBuffer with this source's samples
|
||||
|
@ -295,8 +295,8 @@ int main(int argc, const char* argv[]) {
|
|||
}
|
||||
|
||||
// perform the TwoPole effect on the stkFrameBuffer
|
||||
if (otherAgentTwoPole) {
|
||||
otherAgentTwoPole->tick(stkFrameBuffer);
|
||||
if (otherNodeTwoPole) {
|
||||
otherNodeTwoPole->tick(stkFrameBuffer);
|
||||
}
|
||||
|
||||
for (int s = 0; s < BUFFER_LENGTH_SAMPLES_PER_CHANNEL; s++) {
|
||||
|
@ -319,82 +319,82 @@ int main(int argc, const char* argv[]) {
|
|||
if (s >= BUFFER_LENGTH_SAMPLES_PER_CHANNEL - PHASE_DELAY_AT_90) {
|
||||
// this could be a delayed sample on the next pass
|
||||
// so store the affected back in the ARB
|
||||
otherAgentBuffer->getNextOutput()[s] = (int16_t) stkFrameBuffer[s];
|
||||
otherNodeBuffer->getNextOutput()[s] = (int16_t) stkFrameBuffer[s];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(clientPacket + sizeof(PACKET_HEADER_MIXED_AUDIO), clientSamples, sizeof(clientSamples));
|
||||
agentList->getAgentSocket()->send(agent->getPublicSocket(), clientPacket, sizeof(clientPacket));
|
||||
nodeList->getNodeSocket()->send(node->getPublicSocket(), clientPacket, sizeof(clientPacket));
|
||||
}
|
||||
}
|
||||
|
||||
// push forward the next output pointers for any audio buffers we used
|
||||
for (AgentList::iterator agent = agentList->begin(); agent != agentList->end(); agent++) {
|
||||
PositionalAudioRingBuffer* agentBuffer = (PositionalAudioRingBuffer*) agent->getLinkedData();
|
||||
if (agentBuffer && agentBuffer->willBeAddedToMix()) {
|
||||
agentBuffer->setNextOutput(agentBuffer->getNextOutput() + BUFFER_LENGTH_SAMPLES_PER_CHANNEL);
|
||||
for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
|
||||
PositionalAudioRingBuffer* nodeBuffer = (PositionalAudioRingBuffer*) node->getLinkedData();
|
||||
if (nodeBuffer && nodeBuffer->willBeAddedToMix()) {
|
||||
nodeBuffer->setNextOutput(nodeBuffer->getNextOutput() + BUFFER_LENGTH_SAMPLES_PER_CHANNEL);
|
||||
|
||||
if (agentBuffer->getNextOutput() >= agentBuffer->getBuffer() + RING_BUFFER_LENGTH_SAMPLES) {
|
||||
agentBuffer->setNextOutput(agentBuffer->getBuffer());
|
||||
if (nodeBuffer->getNextOutput() >= nodeBuffer->getBuffer() + RING_BUFFER_LENGTH_SAMPLES) {
|
||||
nodeBuffer->setNextOutput(nodeBuffer->getBuffer());
|
||||
}
|
||||
|
||||
agentBuffer->setWillBeAddedToMix(false);
|
||||
nodeBuffer->setWillBeAddedToMix(false);
|
||||
}
|
||||
}
|
||||
|
||||
// pull any new audio data from agents off of the network stack
|
||||
while (agentList->getAgentSocket()->receive(agentAddress, packetData, &receivedBytes)) {
|
||||
// pull any new audio data from nodes off of the network stack
|
||||
while (nodeList->getNodeSocket()->receive(nodeAddress, packetData, &receivedBytes)) {
|
||||
if (packetData[0] == PACKET_HEADER_MICROPHONE_AUDIO_NO_ECHO ||
|
||||
packetData[0] == PACKET_HEADER_MICROPHONE_AUDIO_WITH_ECHO) {
|
||||
Agent* avatarAgent = agentList->addOrUpdateAgent(agentAddress,
|
||||
agentAddress,
|
||||
AGENT_TYPE_AVATAR,
|
||||
agentList->getLastAgentID());
|
||||
Node* avatarNode = nodeList->addOrUpdateNode(nodeAddress,
|
||||
nodeAddress,
|
||||
NODE_TYPE_AGENT,
|
||||
nodeList->getLastNodeID());
|
||||
|
||||
if (avatarAgent->getAgentID() == agentList->getLastAgentID()) {
|
||||
agentList->increaseAgentID();
|
||||
if (avatarNode->getNodeID() == nodeList->getLastNodeID()) {
|
||||
nodeList->increaseNodeID();
|
||||
}
|
||||
|
||||
agentList->updateAgentWithData(agentAddress, packetData, receivedBytes);
|
||||
nodeList->updateNodeWithData(nodeAddress, packetData, receivedBytes);
|
||||
|
||||
if (std::isnan(((PositionalAudioRingBuffer *)avatarAgent->getLinkedData())->getOrientation().x)) {
|
||||
// kill off this agent - temporary solution to mixer crash on mac sleep
|
||||
avatarAgent->setAlive(false);
|
||||
if (std::isnan(((PositionalAudioRingBuffer *)avatarNode->getLinkedData())->getOrientation().x)) {
|
||||
// kill off this node - temporary solution to mixer crash on mac sleep
|
||||
avatarNode->setAlive(false);
|
||||
}
|
||||
} else if (packetData[0] == PACKET_HEADER_INJECT_AUDIO) {
|
||||
Agent* matchingInjector = NULL;
|
||||
Node* matchingInjector = NULL;
|
||||
|
||||
for (AgentList::iterator agent = agentList->begin(); agent != agentList->end(); agent++) {
|
||||
if (agent->getLinkedData()) {
|
||||
for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
|
||||
if (node->getLinkedData()) {
|
||||
|
||||
InjectedAudioRingBuffer* ringBuffer = (InjectedAudioRingBuffer*) agent->getLinkedData();
|
||||
InjectedAudioRingBuffer* ringBuffer = (InjectedAudioRingBuffer*) node->getLinkedData();
|
||||
if (memcmp(ringBuffer->getStreamIdentifier(),
|
||||
packetData + 1,
|
||||
STREAM_IDENTIFIER_NUM_BYTES) == 0) {
|
||||
// this is the matching stream, assign to matchingInjector and stop looking
|
||||
matchingInjector = &*agent;
|
||||
matchingInjector = &*node;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!matchingInjector) {
|
||||
matchingInjector = agentList->addOrUpdateAgent(NULL,
|
||||
matchingInjector = nodeList->addOrUpdateNode(NULL,
|
||||
NULL,
|
||||
AGENT_TYPE_AUDIO_INJECTOR,
|
||||
agentList->getLastAgentID());
|
||||
agentList->increaseAgentID();
|
||||
NODE_TYPE_AUDIO_INJECTOR,
|
||||
nodeList->getLastNodeID());
|
||||
nodeList->increaseNodeID();
|
||||
|
||||
}
|
||||
|
||||
// give the new audio data to the matching injector agent
|
||||
agentList->updateAgentWithData(matchingInjector, packetData, receivedBytes);
|
||||
// give the new audio data to the matching injector node
|
||||
nodeList->updateNodeWithData(matchingInjector, packetData, receivedBytes);
|
||||
} else if (packetData[0] == PACKET_HEADER_PING) {
|
||||
|
||||
// If the packet is a ping, let processAgentData handle it.
|
||||
agentList->processAgentData(agentAddress, packetData, receivedBytes);
|
||||
// If the packet is a ping, let processNodeData handle it.
|
||||
nodeList->processNodeData(nodeAddress, packetData, receivedBytes);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved
|
||||
//
|
||||
// The avatar mixer receives head, hand and positional data from all connected
|
||||
// agents, and broadcasts that data back to them, every BROADCAST_INTERVAL ms.
|
||||
// nodes, and broadcasts that data back to them, every BROADCAST_INTERVAL ms.
|
||||
//
|
||||
//
|
||||
|
||||
|
@ -25,10 +25,10 @@
|
|||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <AgentList.h>
|
||||
#include <NodeList.h>
|
||||
#include <SharedUtil.h>
|
||||
#include <PacketHeaders.h>
|
||||
#include <AgentTypes.h>
|
||||
#include <NodeTypes.h>
|
||||
#include <StdDev.h>
|
||||
#include <UDPSocket.h>
|
||||
|
||||
|
@ -36,24 +36,24 @@
|
|||
|
||||
const int AVATAR_LISTEN_PORT = 55444;
|
||||
|
||||
unsigned char *addAgentToBroadcastPacket(unsigned char *currentPosition, Agent *agentToAdd) {
|
||||
currentPosition += packAgentId(currentPosition, agentToAdd->getAgentID());
|
||||
unsigned char *addNodeToBroadcastPacket(unsigned char *currentPosition, Node *nodeToAdd) {
|
||||
currentPosition += packNodeId(currentPosition, nodeToAdd->getNodeID());
|
||||
|
||||
AvatarData *agentData = (AvatarData *)agentToAdd->getLinkedData();
|
||||
currentPosition += agentData->getBroadcastData(currentPosition);
|
||||
AvatarData *nodeData = (AvatarData *)nodeToAdd->getLinkedData();
|
||||
currentPosition += nodeData->getBroadcastData(currentPosition);
|
||||
|
||||
return currentPosition;
|
||||
}
|
||||
|
||||
void attachAvatarDataToAgent(Agent* newAgent) {
|
||||
if (newAgent->getLinkedData() == NULL) {
|
||||
newAgent->setLinkedData(new AvatarData(newAgent));
|
||||
void attachAvatarDataToNode(Node* newNode) {
|
||||
if (newNode->getLinkedData() == NULL) {
|
||||
newNode->setLinkedData(new AvatarData(newNode));
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, const char* argv[]) {
|
||||
|
||||
AgentList* agentList = AgentList::createInstance(AGENT_TYPE_AVATAR_MIXER, AVATAR_LISTEN_PORT);
|
||||
NodeList* nodeList = NodeList::createInstance(NODE_TYPE_AVATAR_MIXER, AVATAR_LISTEN_PORT);
|
||||
setvbuf(stdout, NULL, _IOLBF, 0);
|
||||
|
||||
// Handle Local Domain testing with the --local command line
|
||||
|
@ -64,11 +64,11 @@ int main(int argc, const char* argv[]) {
|
|||
sprintf(DOMAIN_IP,"%d.%d.%d.%d", (ip & 0xFF), ((ip >> 8) & 0xFF),((ip >> 16) & 0xFF), ((ip >> 24) & 0xFF));
|
||||
}
|
||||
|
||||
agentList->linkedDataCreateCallback = attachAvatarDataToAgent;
|
||||
nodeList->linkedDataCreateCallback = attachAvatarDataToNode;
|
||||
|
||||
agentList->startSilentAgentRemovalThread();
|
||||
nodeList->startSilentNodeRemovalThread();
|
||||
|
||||
sockaddr *agentAddress = new sockaddr;
|
||||
sockaddr *nodeAddress = new sockaddr;
|
||||
unsigned char *packetData = new unsigned char[MAX_PACKET_SIZE];
|
||||
ssize_t receivedBytes = 0;
|
||||
|
||||
|
@ -77,68 +77,68 @@ int main(int argc, const char* argv[]) {
|
|||
|
||||
unsigned char* currentBufferPosition = NULL;
|
||||
|
||||
uint16_t agentID = 0;
|
||||
Agent* avatarAgent = NULL;
|
||||
uint16_t nodeID = 0;
|
||||
Node* avatarNode = NULL;
|
||||
|
||||
timeval lastDomainServerCheckIn = {};
|
||||
// we only need to hear back about avatar agents from the DS
|
||||
AgentList::getInstance()->setAgentTypesOfInterest(&AGENT_TYPE_AVATAR, 1);
|
||||
// we only need to hear back about avatar nodes from the DS
|
||||
NodeList::getInstance()->setNodeTypesOfInterest(&NODE_TYPE_AGENT, 1);
|
||||
|
||||
while (true) {
|
||||
|
||||
// send a check in packet to the domain server if DOMAIN_SERVER_CHECK_IN_USECS has elapsed
|
||||
if (usecTimestampNow() - usecTimestamp(&lastDomainServerCheckIn) >= DOMAIN_SERVER_CHECK_IN_USECS) {
|
||||
gettimeofday(&lastDomainServerCheckIn, NULL);
|
||||
AgentList::getInstance()->sendDomainServerCheckIn();
|
||||
NodeList::getInstance()->sendDomainServerCheckIn();
|
||||
}
|
||||
|
||||
if (agentList->getAgentSocket()->receive(agentAddress, packetData, &receivedBytes)) {
|
||||
if (nodeList->getNodeSocket()->receive(nodeAddress, packetData, &receivedBytes)) {
|
||||
switch (packetData[0]) {
|
||||
case PACKET_HEADER_HEAD_DATA:
|
||||
// grab the agent ID from the packet
|
||||
unpackAgentId(packetData + 1, &agentID);
|
||||
// grab the node ID from the packet
|
||||
unpackNodeId(packetData + 1, &nodeID);
|
||||
|
||||
// add or update the agent in our list
|
||||
avatarAgent = agentList->addOrUpdateAgent(agentAddress, agentAddress, AGENT_TYPE_AVATAR, agentID);
|
||||
// add or update the node in our list
|
||||
avatarNode = nodeList->addOrUpdateNode(nodeAddress, nodeAddress, NODE_TYPE_AGENT, nodeID);
|
||||
|
||||
// parse positional data from an agent
|
||||
agentList->updateAgentWithData(avatarAgent, packetData, receivedBytes);
|
||||
// parse positional data from an node
|
||||
nodeList->updateNodeWithData(avatarNode, packetData, receivedBytes);
|
||||
case PACKET_HEADER_INJECT_AUDIO:
|
||||
currentBufferPosition = broadcastPacket + 1;
|
||||
|
||||
// send back a packet with other active agent data to this agent
|
||||
for (AgentList::iterator agent = agentList->begin(); agent != agentList->end(); agent++) {
|
||||
if (agent->getLinkedData() && !socketMatch(agentAddress, agent->getActiveSocket())) {
|
||||
currentBufferPosition = addAgentToBroadcastPacket(currentBufferPosition, &*agent);
|
||||
// send back a packet with other active node data to this node
|
||||
for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
|
||||
if (node->getLinkedData() && !socketMatch(nodeAddress, node->getActiveSocket())) {
|
||||
currentBufferPosition = addNodeToBroadcastPacket(currentBufferPosition, &*node);
|
||||
}
|
||||
}
|
||||
|
||||
agentList->getAgentSocket()->send(agentAddress, broadcastPacket, currentBufferPosition - broadcastPacket);
|
||||
nodeList->getNodeSocket()->send(nodeAddress, broadcastPacket, currentBufferPosition - broadcastPacket);
|
||||
|
||||
break;
|
||||
case PACKET_HEADER_AVATAR_VOXEL_URL:
|
||||
// grab the agent ID from the packet
|
||||
unpackAgentId(packetData + 1, &agentID);
|
||||
// grab the node ID from the packet
|
||||
unpackNodeId(packetData + 1, &nodeID);
|
||||
|
||||
// let everyone else know about the update
|
||||
for (AgentList::iterator agent = agentList->begin(); agent != agentList->end(); agent++) {
|
||||
if (agent->getActiveSocket() && agent->getAgentID() != agentID) {
|
||||
agentList->getAgentSocket()->send(agent->getActiveSocket(), packetData, receivedBytes);
|
||||
for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
|
||||
if (node->getActiveSocket() && node->getNodeID() != nodeID) {
|
||||
nodeList->getNodeSocket()->send(node->getActiveSocket(), packetData, receivedBytes);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case PACKET_HEADER_DOMAIN:
|
||||
// ignore the DS packet, for now agents are added only when they communicate directly with us
|
||||
// ignore the DS packet, for now nodes are added only when they communicate directly with us
|
||||
break;
|
||||
default:
|
||||
// hand this off to the AgentList
|
||||
agentList->processAgentData(agentAddress, packetData, receivedBytes);
|
||||
// hand this off to the NodeList
|
||||
nodeList->processNodeData(nodeAddress, packetData, receivedBytes);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
agentList->stopSilentAgentRemovalThread();
|
||||
nodeList->stopSilentNodeRemovalThread();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -5,15 +5,15 @@
|
|||
// Created by Philip Rosedale on 11/20/12.
|
||||
// Copyright (c) 2012 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
// The Domain Server keeps a list of agents that have connected to it, and echoes that list of
|
||||
// agents out to agents when they check in.
|
||||
// The Domain Server keeps a list of nodes that have connected to it, and echoes that list of
|
||||
// nodes out to nodes when they check in.
|
||||
//
|
||||
// The connection is stateless... the domain server will set you inactive if it does not hear from
|
||||
// you in LOGOFF_CHECK_INTERVAL milliseconds, meaning your info will not be sent to other users.
|
||||
//
|
||||
// Each packet from an agent has as first character the type of server:
|
||||
// Each packet from an node has as first character the type of server:
|
||||
//
|
||||
// I - Interactive Agent
|
||||
// I - Interactive Node
|
||||
// M - Audio Mixer
|
||||
//
|
||||
|
||||
|
@ -24,8 +24,8 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "AgentList.h"
|
||||
#include "AgentTypes.h"
|
||||
#include "NodeList.h"
|
||||
#include "NodeTypes.h"
|
||||
#include "Logstash.h"
|
||||
#include "PacketHeaders.h"
|
||||
#include "SharedUtil.h"
|
||||
|
@ -35,12 +35,12 @@ unsigned char packetData[MAX_PACKET_SIZE];
|
|||
|
||||
const int NODE_COUNT_STAT_INTERVAL_MSECS = 5000;
|
||||
|
||||
unsigned char* addAgentToBroadcastPacket(unsigned char* currentPosition, Agent* agentToAdd) {
|
||||
*currentPosition++ = agentToAdd->getType();
|
||||
unsigned char* addNodeToBroadcastPacket(unsigned char* currentPosition, Node* nodeToAdd) {
|
||||
*currentPosition++ = nodeToAdd->getType();
|
||||
|
||||
currentPosition += packAgentId(currentPosition, agentToAdd->getAgentID());
|
||||
currentPosition += packSocket(currentPosition, agentToAdd->getPublicSocket());
|
||||
currentPosition += packSocket(currentPosition, agentToAdd->getLocalSocket());
|
||||
currentPosition += packNodeId(currentPosition, nodeToAdd->getNodeID());
|
||||
currentPosition += packSocket(currentPosition, nodeToAdd->getPublicSocket());
|
||||
currentPosition += packSocket(currentPosition, nodeToAdd->getLocalSocket());
|
||||
|
||||
// return the new unsigned char * for broadcast packet
|
||||
return currentPosition;
|
||||
|
@ -48,7 +48,7 @@ unsigned char* addAgentToBroadcastPacket(unsigned char* currentPosition, Agent*
|
|||
|
||||
int main(int argc, const char * argv[])
|
||||
{
|
||||
AgentList* agentList = AgentList::createInstance(AGENT_TYPE_DOMAIN, DOMAIN_LISTEN_PORT);
|
||||
NodeList* nodeList = NodeList::createInstance(NODE_TYPE_DOMAIN, DOMAIN_LISTEN_PORT);
|
||||
// If user asks to run in "local" mode then we do NOT replace the IP
|
||||
// with the EC2 IP. Otherwise, we will replace the IP like we used to
|
||||
// this allows developers to run a local domain without recompiling the
|
||||
|
@ -67,7 +67,7 @@ int main(int argc, const char * argv[])
|
|||
setvbuf(stdout, NULL, _IOLBF, 0);
|
||||
|
||||
ssize_t receivedBytes = 0;
|
||||
char agentType = '\0';
|
||||
char nodeType = '\0';
|
||||
|
||||
unsigned char broadcastPacket[MAX_PACKET_SIZE];
|
||||
broadcastPacket[0] = PACKET_HEADER_DOMAIN;
|
||||
|
@ -75,113 +75,113 @@ int main(int argc, const char * argv[])
|
|||
unsigned char* currentBufferPos;
|
||||
unsigned char* startPointer;
|
||||
|
||||
sockaddr_in agentPublicAddress, agentLocalAddress;
|
||||
agentLocalAddress.sin_family = AF_INET;
|
||||
sockaddr_in nodePublicAddress, nodeLocalAddress;
|
||||
nodeLocalAddress.sin_family = AF_INET;
|
||||
|
||||
in_addr_t serverLocalAddress = getLocalAddress();
|
||||
|
||||
agentList->startSilentAgentRemovalThread();
|
||||
nodeList->startSilentNodeRemovalThread();
|
||||
|
||||
timeval lastStatSendTime = {};
|
||||
|
||||
while (true) {
|
||||
if (agentList->getAgentSocket()->receive((sockaddr *)&agentPublicAddress, packetData, &receivedBytes) &&
|
||||
if (nodeList->getNodeSocket()->receive((sockaddr *)&nodePublicAddress, packetData, &receivedBytes) &&
|
||||
(packetData[0] == PACKET_HEADER_DOMAIN_REPORT_FOR_DUTY || packetData[0] == PACKET_HEADER_DOMAIN_LIST_REQUEST)) {
|
||||
std::map<char, Agent *> newestSoloAgents;
|
||||
std::map<char, Node *> newestSoloNodes;
|
||||
|
||||
agentType = packetData[1];
|
||||
int numBytesSocket = unpackSocket(packetData + sizeof(PACKET_HEADER) + sizeof(AGENT_TYPE),
|
||||
(sockaddr*) &agentLocalAddress);
|
||||
nodeType = packetData[1];
|
||||
int numBytesSocket = unpackSocket(packetData + sizeof(PACKET_HEADER) + sizeof(NODE_TYPE),
|
||||
(sockaddr*) &nodeLocalAddress);
|
||||
|
||||
sockaddr* destinationSocket = (sockaddr*) &agentPublicAddress;
|
||||
sockaddr* destinationSocket = (sockaddr*) &nodePublicAddress;
|
||||
|
||||
// check the agent public address
|
||||
// check the node public address
|
||||
// if it matches our local address we're on the same box
|
||||
// so hardcode the EC2 public address for now
|
||||
if (agentPublicAddress.sin_addr.s_addr == serverLocalAddress) {
|
||||
if (nodePublicAddress.sin_addr.s_addr == serverLocalAddress) {
|
||||
// If we're not running "local" then we do replace the IP
|
||||
// with the EC2 IP. Otherwise, we use our normal public IP
|
||||
if (!isLocalMode) {
|
||||
agentPublicAddress.sin_addr.s_addr = 895283510; // local IP in this format...
|
||||
destinationSocket = (sockaddr*) &agentLocalAddress;
|
||||
nodePublicAddress.sin_addr.s_addr = 895283510; // local IP in this format...
|
||||
destinationSocket = (sockaddr*) &nodeLocalAddress;
|
||||
}
|
||||
}
|
||||
|
||||
Agent* newAgent = agentList->addOrUpdateAgent((sockaddr*) &agentPublicAddress,
|
||||
(sockaddr*) &agentLocalAddress,
|
||||
agentType,
|
||||
agentList->getLastAgentID());
|
||||
Node* newNode = nodeList->addOrUpdateNode((sockaddr*) &nodePublicAddress,
|
||||
(sockaddr*) &nodeLocalAddress,
|
||||
nodeType,
|
||||
nodeList->getLastNodeID());
|
||||
|
||||
if (newAgent->getAgentID() == agentList->getLastAgentID()) {
|
||||
agentList->increaseAgentID();
|
||||
if (newNode->getNodeID() == nodeList->getLastNodeID()) {
|
||||
nodeList->increaseNodeID();
|
||||
}
|
||||
|
||||
currentBufferPos = broadcastPacket + sizeof(PACKET_HEADER);
|
||||
startPointer = currentBufferPos;
|
||||
|
||||
unsigned char* agentTypesOfInterest = packetData + sizeof(PACKET_HEADER) + sizeof(AGENT_TYPE)
|
||||
unsigned char* nodeTypesOfInterest = packetData + sizeof(PACKET_HEADER) + sizeof(NODE_TYPE)
|
||||
+ numBytesSocket + sizeof(unsigned char);
|
||||
int numInterestTypes = *(agentTypesOfInterest - 1);
|
||||
int numInterestTypes = *(nodeTypesOfInterest - 1);
|
||||
|
||||
if (numInterestTypes > 0) {
|
||||
// if the agent has sent no types of interest, assume they want nothing but their own ID back
|
||||
for (AgentList::iterator agent = agentList->begin(); agent != agentList->end(); agent++) {
|
||||
if (!agent->matches((sockaddr*) &agentPublicAddress, (sockaddr*) &agentLocalAddress, agentType) &&
|
||||
memchr(agentTypesOfInterest, agent->getType(), numInterestTypes)) {
|
||||
// this is not the agent themselves
|
||||
// and this is an agent of a type in the passed agent types of interest
|
||||
// or the agent did not pass us any specific types they are interested in
|
||||
// if the node has sent no types of interest, assume they want nothing but their own ID back
|
||||
for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
|
||||
if (!node->matches((sockaddr*) &nodePublicAddress, (sockaddr*) &nodeLocalAddress, nodeType) &&
|
||||
memchr(nodeTypesOfInterest, node->getType(), numInterestTypes)) {
|
||||
// this is not the node themselves
|
||||
// and this is an node of a type in the passed node types of interest
|
||||
// or the node did not pass us any specific types they are interested in
|
||||
|
||||
if (memchr(SOLO_AGENT_TYPES, agent->getType(), sizeof(SOLO_AGENT_TYPES)) == NULL) {
|
||||
// this is an agent of which there can be multiple, just add them to the packet
|
||||
// don't send avatar agents to other avatars, that will come from avatar mixer
|
||||
if (agentType != AGENT_TYPE_AVATAR || agent->getType() != AGENT_TYPE_AVATAR) {
|
||||
currentBufferPos = addAgentToBroadcastPacket(currentBufferPos, &(*agent));
|
||||
if (memchr(SOLO_NODE_TYPES, node->getType(), sizeof(SOLO_NODE_TYPES)) == NULL) {
|
||||
// this is an node of which there can be multiple, just add them to the packet
|
||||
// don't send avatar nodes to other avatars, that will come from avatar mixer
|
||||
if (nodeType != NODE_TYPE_AGENT || node->getType() != NODE_TYPE_AGENT) {
|
||||
currentBufferPos = addNodeToBroadcastPacket(currentBufferPos, &(*node));
|
||||
}
|
||||
|
||||
} else {
|
||||
// solo agent, we need to only send newest
|
||||
if (newestSoloAgents[agent->getType()] == NULL ||
|
||||
newestSoloAgents[agent->getType()]->getWakeMicrostamp() < agent->getWakeMicrostamp()) {
|
||||
// we have to set the newer solo agent to add it to the broadcast later
|
||||
newestSoloAgents[agent->getType()] = &(*agent);
|
||||
// solo node, we need to only send newest
|
||||
if (newestSoloNodes[node->getType()] == NULL ||
|
||||
newestSoloNodes[node->getType()]->getWakeMicrostamp() < node->getWakeMicrostamp()) {
|
||||
// we have to set the newer solo node to add it to the broadcast later
|
||||
newestSoloNodes[node->getType()] = &(*node);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (std::map<char, Agent *>::iterator soloAgent = newestSoloAgents.begin();
|
||||
soloAgent != newestSoloAgents.end();
|
||||
soloAgent++) {
|
||||
// this is the newest alive solo agent, add them to the packet
|
||||
currentBufferPos = addAgentToBroadcastPacket(currentBufferPos, soloAgent->second);
|
||||
for (std::map<char, Node *>::iterator soloNode = newestSoloNodes.begin();
|
||||
soloNode != newestSoloNodes.end();
|
||||
soloNode++) {
|
||||
// this is the newest alive solo node, add them to the packet
|
||||
currentBufferPos = addNodeToBroadcastPacket(currentBufferPos, soloNode->second);
|
||||
}
|
||||
}
|
||||
|
||||
// update last receive to now
|
||||
long long timeNow = usecTimestampNow();
|
||||
newAgent->setLastHeardMicrostamp(timeNow);
|
||||
newNode->setLastHeardMicrostamp(timeNow);
|
||||
|
||||
if (packetData[0] == PACKET_HEADER_DOMAIN_REPORT_FOR_DUTY
|
||||
&& memchr(SOLO_AGENT_TYPES, agentType, sizeof(SOLO_AGENT_TYPES))) {
|
||||
newAgent->setWakeMicrostamp(timeNow);
|
||||
&& memchr(SOLO_NODE_TYPES, nodeType, sizeof(SOLO_NODE_TYPES))) {
|
||||
newNode->setWakeMicrostamp(timeNow);
|
||||
}
|
||||
|
||||
// add the agent ID to the end of the pointer
|
||||
currentBufferPos += packAgentId(currentBufferPos, newAgent->getAgentID());
|
||||
// add the node ID to the end of the pointer
|
||||
currentBufferPos += packNodeId(currentBufferPos, newNode->getNodeID());
|
||||
|
||||
// send the constructed list back to this agent
|
||||
agentList->getAgentSocket()->send(destinationSocket,
|
||||
// send the constructed list back to this node
|
||||
nodeList->getNodeSocket()->send(destinationSocket,
|
||||
broadcastPacket,
|
||||
(currentBufferPos - startPointer) + 1);
|
||||
}
|
||||
|
||||
if (Logstash::shouldSendStats()) {
|
||||
if (usecTimestampNow() - usecTimestamp(&lastStatSendTime) >= (NODE_COUNT_STAT_INTERVAL_MSECS * 1000)) {
|
||||
// time to send our count of agents and servers to logstash
|
||||
// time to send our count of nodes and servers to logstash
|
||||
const char NODE_COUNT_LOGSTASH_KEY[] = "ds-node-count";
|
||||
|
||||
Logstash::stashValue(STAT_TYPE_TIMER, NODE_COUNT_LOGSTASH_KEY, agentList->getNumAliveAgents());
|
||||
Logstash::stashValue(STAT_TYPE_TIMER, NODE_COUNT_LOGSTASH_KEY, nodeList->getNumAliveNodes());
|
||||
|
||||
gettimeofday(&lastStatSendTime, NULL);
|
||||
}
|
||||
|
|
|
@ -11,14 +11,14 @@
|
|||
#include <cstring>
|
||||
|
||||
#include <SharedUtil.h>
|
||||
#include <AgentTypes.h>
|
||||
#include <NodeTypes.h>
|
||||
#include <PacketHeaders.h>
|
||||
#include <AgentList.h>
|
||||
#include <NodeList.h>
|
||||
#include <AvatarData.h>
|
||||
#include <AudioInjectionManager.h>
|
||||
#include <AudioInjector.h>
|
||||
|
||||
const int EVE_AGENT_LISTEN_PORT = 55441;
|
||||
const int EVE_NODE_LISTEN_PORT = 55441;
|
||||
|
||||
const float RANDOM_POSITION_MAX_DIMENSION = 10.0f;
|
||||
|
||||
|
@ -39,27 +39,27 @@ const int EVE_VOLUME_BYTE = 190;
|
|||
|
||||
const char EVE_AUDIO_FILENAME[] = "/etc/highfidelity/eve/resources/eve.raw";
|
||||
|
||||
bool stopReceiveAgentDataThread;
|
||||
bool stopReceiveNodeDataThread;
|
||||
|
||||
void *receiveAgentData(void *args) {
|
||||
void *receiveNodeData(void *args) {
|
||||
sockaddr senderAddress;
|
||||
ssize_t bytesReceived;
|
||||
unsigned char incomingPacket[MAX_PACKET_SIZE];
|
||||
|
||||
AgentList* agentList = AgentList::getInstance();
|
||||
NodeList* nodeList = NodeList::getInstance();
|
||||
|
||||
while (!::stopReceiveAgentDataThread) {
|
||||
if (agentList->getAgentSocket()->receive(&senderAddress, incomingPacket, &bytesReceived)) {
|
||||
while (!::stopReceiveNodeDataThread) {
|
||||
if (nodeList->getNodeSocket()->receive(&senderAddress, incomingPacket, &bytesReceived)) {
|
||||
switch (incomingPacket[0]) {
|
||||
case PACKET_HEADER_BULK_AVATAR_DATA:
|
||||
// this is the positional data for other agents
|
||||
// pass that off to the agentList processBulkAgentData method
|
||||
agentList->processBulkAgentData(&senderAddress, incomingPacket, bytesReceived);
|
||||
// this is the positional data for other nodes
|
||||
// pass that off to the nodeList processBulkNodeData method
|
||||
nodeList->processBulkNodeData(&senderAddress, incomingPacket, bytesReceived);
|
||||
|
||||
break;
|
||||
default:
|
||||
// have the agentList handle list of agents from DS, replies from other agents, etc.
|
||||
agentList->processAgentData(&senderAddress, incomingPacket, bytesReceived);
|
||||
// have the nodeList handle list of nodes from DS, replies from other nodes, etc.
|
||||
nodeList->processNodeData(&senderAddress, incomingPacket, bytesReceived);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -69,9 +69,9 @@ void *receiveAgentData(void *args) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
void createAvatarDataForAgent(Agent* agent) {
|
||||
if (!agent->getLinkedData()) {
|
||||
agent->setLinkedData(new AvatarData(agent));
|
||||
void createAvatarDataForNode(Node* node) {
|
||||
if (!node->getLinkedData()) {
|
||||
node->setLinkedData(new AvatarData(node));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -79,17 +79,17 @@ int main(int argc, const char* argv[]) {
|
|||
// new seed for random audio sleep times
|
||||
srand(time(0));
|
||||
|
||||
// create an AgentList instance to handle communication with other agents
|
||||
AgentList* agentList = AgentList::createInstance(AGENT_TYPE_AVATAR, EVE_AGENT_LISTEN_PORT);
|
||||
// create an NodeList instance to handle communication with other nodes
|
||||
NodeList* nodeList = NodeList::createInstance(NODE_TYPE_AGENT, EVE_NODE_LISTEN_PORT);
|
||||
|
||||
// start the agent list thread that will kill off agents when they stop talking
|
||||
agentList->startSilentAgentRemovalThread();
|
||||
// start the node list thread that will kill off nodes when they stop talking
|
||||
nodeList->startSilentNodeRemovalThread();
|
||||
|
||||
// start the ping thread that hole punches to create an active connection to other agents
|
||||
agentList->startPingUnknownAgentsThread();
|
||||
// start the ping thread that hole punches to create an active connection to other nodes
|
||||
nodeList->startPingUnknownNodesThread();
|
||||
|
||||
pthread_t receiveAgentDataThread;
|
||||
pthread_create(&receiveAgentDataThread, NULL, receiveAgentData, NULL);
|
||||
pthread_t receiveNodeDataThread;
|
||||
pthread_create(&receiveNodeDataThread, NULL, receiveNodeData, NULL);
|
||||
|
||||
// create an AvatarData object, "eve"
|
||||
AvatarData eve;
|
||||
|
@ -109,8 +109,8 @@ int main(int argc, const char* argv[]) {
|
|||
0.5,
|
||||
eve.getPosition()[2] + 0.1));
|
||||
|
||||
// prepare the audio injection manager by giving it a handle to our agent socket
|
||||
AudioInjectionManager::setInjectorSocket(agentList->getAgentSocket());
|
||||
// prepare the audio injection manager by giving it a handle to our node socket
|
||||
AudioInjectionManager::setInjectorSocket(nodeList->getNodeSocket());
|
||||
|
||||
// read eve's audio data
|
||||
AudioInjector eveAudioInjector(EVE_AUDIO_FILENAME);
|
||||
|
@ -121,8 +121,8 @@ int main(int argc, const char* argv[]) {
|
|||
// set the position of the audio injector
|
||||
eveAudioInjector.setPosition(eve.getPosition());
|
||||
|
||||
// register the callback for agent data creation
|
||||
agentList->linkedDataCreateCallback = createAvatarDataForAgent;
|
||||
// register the callback for node data creation
|
||||
nodeList->linkedDataCreateCallback = createAvatarDataForNode;
|
||||
|
||||
unsigned char broadcastPacket[MAX_PACKET_SIZE];
|
||||
broadcastPacket[0] = PACKET_HEADER_HEAD_DATA;
|
||||
|
@ -135,46 +135,46 @@ int main(int argc, const char* argv[]) {
|
|||
timeval lastDomainServerCheckIn = {};
|
||||
|
||||
// eve wants to hear about an avatar mixer and an audio mixer from the domain server
|
||||
const char EVE_AGENT_TYPES_OF_INTEREST[] = {AGENT_TYPE_AVATAR_MIXER, AGENT_TYPE_AUDIO_MIXER};
|
||||
AgentList::getInstance()->setAgentTypesOfInterest(EVE_AGENT_TYPES_OF_INTEREST, sizeof(EVE_AGENT_TYPES_OF_INTEREST));
|
||||
const char EVE_NODE_TYPES_OF_INTEREST[] = {NODE_TYPE_AVATAR_MIXER, NODE_TYPE_AUDIO_MIXER};
|
||||
NodeList::getInstance()->setNodeTypesOfInterest(EVE_NODE_TYPES_OF_INTEREST, sizeof(EVE_NODE_TYPES_OF_INTEREST));
|
||||
|
||||
while (true) {
|
||||
// send a check in packet to the domain server if DOMAIN_SERVER_CHECK_IN_USECS has elapsed
|
||||
if (usecTimestampNow() - usecTimestamp(&lastDomainServerCheckIn) >= DOMAIN_SERVER_CHECK_IN_USECS) {
|
||||
gettimeofday(&lastDomainServerCheckIn, NULL);
|
||||
AgentList::getInstance()->sendDomainServerCheckIn();
|
||||
NodeList::getInstance()->sendDomainServerCheckIn();
|
||||
}
|
||||
|
||||
// update the thisSend timeval to the current time
|
||||
gettimeofday(&thisSend, NULL);
|
||||
|
||||
// find the current avatar mixer
|
||||
Agent* avatarMixer = agentList->soloAgentOfType(AGENT_TYPE_AVATAR_MIXER);
|
||||
Node* avatarMixer = nodeList->soloNodeOfType(NODE_TYPE_AVATAR_MIXER);
|
||||
|
||||
// make sure we actually have an avatar mixer with an active socket
|
||||
if (agentList->getOwnerID() != UNKNOWN_AGENT_ID && avatarMixer && avatarMixer->getActiveSocket() != NULL) {
|
||||
if (nodeList->getOwnerID() != UNKNOWN_NODE_ID && avatarMixer && avatarMixer->getActiveSocket() != NULL) {
|
||||
unsigned char* packetPosition = broadcastPacket + sizeof(PACKET_HEADER);
|
||||
packetPosition += packAgentId(packetPosition, agentList->getOwnerID());
|
||||
packetPosition += packNodeId(packetPosition, nodeList->getOwnerID());
|
||||
|
||||
// use the getBroadcastData method in the AvatarData class to populate the broadcastPacket buffer
|
||||
packetPosition += eve.getBroadcastData(packetPosition);
|
||||
|
||||
// use the UDPSocket instance attached to our agent list to send avatar data to mixer
|
||||
agentList->getAgentSocket()->send(avatarMixer->getActiveSocket(), broadcastPacket, packetPosition - broadcastPacket);
|
||||
// use the UDPSocket instance attached to our node list to send avatar data to mixer
|
||||
nodeList->getNodeSocket()->send(avatarMixer->getActiveSocket(), broadcastPacket, packetPosition - broadcastPacket);
|
||||
}
|
||||
|
||||
if (!eveAudioInjector.isInjectingAudio()) {
|
||||
// enumerate the other agents to decide if one is close enough that eve should talk
|
||||
for (AgentList::iterator agent = agentList->begin(); agent != agentList->end(); agent++) {
|
||||
AvatarData* avatarData = (AvatarData*) agent->getLinkedData();
|
||||
// enumerate the other nodes to decide if one is close enough that eve should talk
|
||||
for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
|
||||
AvatarData* avatarData = (AvatarData*) node->getLinkedData();
|
||||
|
||||
if (avatarData) {
|
||||
glm::vec3 tempVector = eve.getPosition() - avatarData->getPosition();
|
||||
float squareDistance = glm::dot(tempVector, tempVector);
|
||||
|
||||
if (squareDistance <= AUDIO_INJECT_PROXIMITY) {
|
||||
// look for an audio mixer in our agent list
|
||||
Agent* audioMixer = AgentList::getInstance()->soloAgentOfType(AGENT_TYPE_AUDIO_MIXER);
|
||||
// look for an audio mixer in our node list
|
||||
Node* audioMixer = NodeList::getInstance()->soloNodeOfType(NODE_TYPE_AUDIO_MIXER);
|
||||
|
||||
if (audioMixer) {
|
||||
// update the destination socket for the AIM, in case the mixer has changed
|
||||
|
@ -205,11 +205,11 @@ int main(int argc, const char* argv[]) {
|
|||
}
|
||||
}
|
||||
|
||||
// stop the receive agent data thread
|
||||
stopReceiveAgentDataThread = true;
|
||||
pthread_join(receiveAgentDataThread, NULL);
|
||||
// stop the receive node data thread
|
||||
stopReceiveNodeDataThread = true;
|
||||
pthread_join(receiveNodeDataThread, NULL);
|
||||
|
||||
// stop the agent list's threads
|
||||
agentList->stopPingUnknownAgentsThread();
|
||||
agentList->stopSilentAgentRemovalThread();
|
||||
// stop the node list's threads
|
||||
nodeList->stopPingUnknownNodesThread();
|
||||
nodeList->stopSilentNodeRemovalThread();
|
||||
}
|
||||
|
|
|
@ -14,8 +14,8 @@
|
|||
#include <string.h>
|
||||
#include <sstream>
|
||||
|
||||
#include <AgentList.h>
|
||||
#include <AgentTypes.h>
|
||||
#include <NodeList.h>
|
||||
#include <NodeTypes.h>
|
||||
#include <AvatarData.h>
|
||||
#include <SharedUtil.h>
|
||||
#include <PacketHeaders.h>
|
||||
|
@ -104,9 +104,9 @@ bool processParameters(int parameterCount, char* parameterData[]) {
|
|||
return true;
|
||||
};
|
||||
|
||||
void createAvatarDataForAgent(Agent* agent) {
|
||||
if (!agent->getLinkedData()) {
|
||||
agent->setLinkedData(new AvatarData(agent));
|
||||
void createAvatarDataForNode(Node* node) {
|
||||
if (!node->getLinkedData()) {
|
||||
node->setLinkedData(new AvatarData(node));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -123,11 +123,11 @@ int main(int argc, char* argv[]) {
|
|||
} else {
|
||||
AudioInjector injector(sourceAudioFile);
|
||||
|
||||
// create an AgentList instance to handle communication with other agents
|
||||
AgentList* agentList = AgentList::createInstance(AGENT_TYPE_AUDIO_INJECTOR, AUDIO_UDP_SEND_PORT);
|
||||
// create an NodeList instance to handle communication with other nodes
|
||||
NodeList* nodeList = NodeList::createInstance(NODE_TYPE_AUDIO_INJECTOR, AUDIO_UDP_SEND_PORT);
|
||||
|
||||
// start the agent list thread that will kill off agents when they stop talking
|
||||
agentList->startSilentAgentRemovalThread();
|
||||
// start the node list thread that will kill off nodes when they stop talking
|
||||
nodeList->startSilentNodeRemovalThread();
|
||||
|
||||
injector.setPosition(glm::vec3(::floatArguments[INJECTOR_POSITION_X],
|
||||
::floatArguments[INJECTOR_POSITION_Y],
|
||||
|
@ -140,8 +140,8 @@ int main(int argc, char* argv[]) {
|
|||
injector.setRadius(::radius);
|
||||
}
|
||||
|
||||
// register the callback for agent data creation
|
||||
agentList->linkedDataCreateCallback = createAvatarDataForAgent;
|
||||
// register the callback for node data creation
|
||||
nodeList->linkedDataCreateCallback = createAvatarDataForNode;
|
||||
|
||||
timeval lastSend = {};
|
||||
unsigned char broadcastPacket = PACKET_HEADER_INJECT_AUDIO;
|
||||
|
@ -153,40 +153,40 @@ int main(int argc, char* argv[]) {
|
|||
unsigned char incomingPacket[MAX_PACKET_SIZE];
|
||||
|
||||
// the audio injector needs to know about the avatar mixer and the audio mixer
|
||||
const char INJECTOR_AGENTS_OF_INTEREST[] = {AGENT_TYPE_AUDIO_MIXER, AGENT_TYPE_AVATAR_MIXER};
|
||||
const char INJECTOR_NODES_OF_INTEREST[] = {NODE_TYPE_AUDIO_MIXER, NODE_TYPE_AVATAR_MIXER};
|
||||
|
||||
int bytesAgentsOfInterest = (::triggerDistance > 0)
|
||||
? sizeof(INJECTOR_AGENTS_OF_INTEREST)
|
||||
: sizeof(INJECTOR_AGENTS_OF_INTEREST) - 1;
|
||||
int bytesNodesOfInterest = (::triggerDistance > 0)
|
||||
? sizeof(INJECTOR_NODES_OF_INTEREST)
|
||||
: sizeof(INJECTOR_NODES_OF_INTEREST) - 1;
|
||||
|
||||
AgentList::getInstance()->setAgentTypesOfInterest(INJECTOR_AGENTS_OF_INTEREST, bytesAgentsOfInterest);
|
||||
NodeList::getInstance()->setNodeTypesOfInterest(INJECTOR_NODES_OF_INTEREST, bytesNodesOfInterest);
|
||||
|
||||
while (true) {
|
||||
// send a check in packet to the domain server if DOMAIN_SERVER_CHECK_IN_USECS has elapsed
|
||||
if (usecTimestampNow() - usecTimestamp(&lastDomainServerCheckIn) >= DOMAIN_SERVER_CHECK_IN_USECS) {
|
||||
gettimeofday(&lastDomainServerCheckIn, NULL);
|
||||
AgentList::getInstance()->sendDomainServerCheckIn();
|
||||
NodeList::getInstance()->sendDomainServerCheckIn();
|
||||
}
|
||||
|
||||
while (agentList->getAgentSocket()->receive(&senderAddress, incomingPacket, &bytesReceived)) {
|
||||
while (nodeList->getNodeSocket()->receive(&senderAddress, incomingPacket, &bytesReceived)) {
|
||||
switch (incomingPacket[0]) {
|
||||
case PACKET_HEADER_BULK_AVATAR_DATA:
|
||||
// this is the positional data for other agents
|
||||
// pass that off to the agentList processBulkAgentData method
|
||||
agentList->processBulkAgentData(&senderAddress, incomingPacket, bytesReceived);
|
||||
// this is the positional data for other nodes
|
||||
// pass that off to the nodeList processBulkNodeData method
|
||||
nodeList->processBulkNodeData(&senderAddress, incomingPacket, bytesReceived);
|
||||
break;
|
||||
default:
|
||||
// have the agentList handle list of agents from DS, replies from other agents, etc.
|
||||
agentList->processAgentData(&senderAddress, incomingPacket, bytesReceived);
|
||||
// have the nodeList handle list of nodes from DS, replies from other nodes, etc.
|
||||
nodeList->processNodeData(&senderAddress, incomingPacket, bytesReceived);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (::triggerDistance) {
|
||||
if (!injector.isInjectingAudio()) {
|
||||
// enumerate the other agents to decide if one is close enough that we should inject
|
||||
for (AgentList::iterator agent = agentList->begin(); agent != agentList->end(); agent++) {
|
||||
AvatarData* avatarData = (AvatarData*) agent->getLinkedData();
|
||||
// enumerate the other nodes to decide if one is close enough that we should inject
|
||||
for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
|
||||
AvatarData* avatarData = (AvatarData*) node->getLinkedData();
|
||||
|
||||
if (avatarData) {
|
||||
glm::vec3 tempVector = injector.getPosition() - avatarData->getPosition();
|
||||
|
@ -200,7 +200,7 @@ int main(int argc, char* argv[]) {
|
|||
}
|
||||
|
||||
// find the current avatar mixer
|
||||
Agent* avatarMixer = agentList->soloAgentOfType(AGENT_TYPE_AVATAR_MIXER);
|
||||
Node* avatarMixer = nodeList->soloNodeOfType(NODE_TYPE_AVATAR_MIXER);
|
||||
|
||||
// make sure we actually have an avatar mixer with an active socket
|
||||
if (avatarMixer && avatarMixer->getActiveSocket() != NULL
|
||||
|
@ -209,8 +209,8 @@ int main(int argc, char* argv[]) {
|
|||
// update the lastSend timeval to the current time
|
||||
gettimeofday(&lastSend, NULL);
|
||||
|
||||
// use the UDPSocket instance attached to our agent list to ask avatar mixer for a list of avatars
|
||||
agentList->getAgentSocket()->send(avatarMixer->getActiveSocket(),
|
||||
// use the UDPSocket instance attached to our node list to ask avatar mixer for a list of avatars
|
||||
nodeList->getNodeSocket()->send(avatarMixer->getActiveSocket(),
|
||||
&broadcastPacket,
|
||||
sizeof(broadcastPacket));
|
||||
}
|
||||
|
@ -223,8 +223,8 @@ int main(int argc, char* argv[]) {
|
|||
}
|
||||
}
|
||||
|
||||
// stop the agent list's threads
|
||||
agentList->stopSilentAgentRemovalThread();
|
||||
// stop the node list's threads
|
||||
nodeList->stopSilentNodeRemovalThread();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,7 +46,7 @@
|
|||
#include <QFileDialog>
|
||||
#include <QDesktopServices>
|
||||
|
||||
#include <AgentTypes.h>
|
||||
#include <NodeTypes.h>
|
||||
#include <AudioInjectionManager.h>
|
||||
#include <AudioInjector.h>
|
||||
#include <Logstash.h>
|
||||
|
@ -73,7 +73,7 @@ static char STAR_CACHE_FILE[] = "cachedStars.txt";
|
|||
|
||||
static const int BANDWIDTH_METER_CLICK_MAX_DRAG_LENGTH = 6; // farther dragged clicks are ignored
|
||||
|
||||
const glm::vec3 START_LOCATION(4.f, 0.f, 5.f); // Where one's own agent begins in the world
|
||||
const glm::vec3 START_LOCATION(4.f, 0.f, 5.f); // Where one's own node begins in the world
|
||||
// (will be overwritten if avatar data file is found)
|
||||
|
||||
const int IDLE_SIMULATE_MSECS = 16; // How often should call simulate and other stuff
|
||||
|
@ -211,11 +211,11 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
|
|||
listenPort = atoi(portStr);
|
||||
}
|
||||
|
||||
AgentList::createInstance(AGENT_TYPE_AVATAR, listenPort);
|
||||
NodeList::createInstance(NODE_TYPE_AGENT, listenPort);
|
||||
|
||||
_enableNetworkThread = !cmdOptionExists(argc, constArgv, "--nonblocking");
|
||||
if (!_enableNetworkThread) {
|
||||
AgentList::getInstance()->getAgentSocket()->setBlocking(false);
|
||||
NodeList::getInstance()->getNodeSocket()->setBlocking(false);
|
||||
}
|
||||
|
||||
const char* domainIP = getCmdOption(argc, constArgv, "--domain");
|
||||
|
@ -234,21 +234,21 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
|
|||
// Voxel File.
|
||||
_voxelsFilename = getCmdOption(argc, constArgv, "-i");
|
||||
|
||||
// the callback for our instance of AgentList is attachNewHeadToAgent
|
||||
AgentList::getInstance()->linkedDataCreateCallback = &attachNewHeadToAgent;
|
||||
// the callback for our instance of NodeList is attachNewHeadToNode
|
||||
NodeList::getInstance()->linkedDataCreateCallback = &attachNewHeadToNode;
|
||||
|
||||
#ifdef _WIN32
|
||||
WSADATA WsaData;
|
||||
int wsaresult = WSAStartup(MAKEWORD(2,2), &WsaData);
|
||||
#endif
|
||||
|
||||
// tell the AgentList instance who to tell the domain server we care about
|
||||
const char agentTypesOfInterest[] = {AGENT_TYPE_AUDIO_MIXER, AGENT_TYPE_AVATAR_MIXER, AGENT_TYPE_VOXEL_SERVER};
|
||||
AgentList::getInstance()->setAgentTypesOfInterest(agentTypesOfInterest, sizeof(agentTypesOfInterest));
|
||||
// tell the NodeList instance who to tell the domain server we care about
|
||||
const char nodeTypesOfInterest[] = {NODE_TYPE_AUDIO_MIXER, NODE_TYPE_AVATAR_MIXER, NODE_TYPE_VOXEL_SERVER};
|
||||
NodeList::getInstance()->setNodeTypesOfInterest(nodeTypesOfInterest, sizeof(nodeTypesOfInterest));
|
||||
|
||||
// start the agentList threads
|
||||
AgentList::getInstance()->startSilentAgentRemovalThread();
|
||||
AgentList::getInstance()->startPingUnknownAgentsThread();
|
||||
// start the nodeList threads
|
||||
NodeList::getInstance()->startSilentNodeRemovalThread();
|
||||
NodeList::getInstance()->startPingUnknownNodesThread();
|
||||
|
||||
_window->setCentralWidget(_glWidget);
|
||||
|
||||
|
@ -485,17 +485,17 @@ void Application::resizeGL(int width, int height) {
|
|||
glLoadIdentity();
|
||||
}
|
||||
|
||||
void Application::broadcastToAgents(unsigned char* data, size_t bytes, const char type) {
|
||||
void Application::broadcastToNodes(unsigned char* data, size_t bytes, const char type) {
|
||||
|
||||
int n = AgentList::getInstance()->broadcastToAgents(data, bytes, &type, 1);
|
||||
int n = NodeList::getInstance()->broadcastToNodes(data, bytes, &type, 1);
|
||||
|
||||
BandwidthMeter::ChannelIndex channel;
|
||||
switch (type) {
|
||||
case AGENT_TYPE_AVATAR:
|
||||
case AGENT_TYPE_AVATAR_MIXER:
|
||||
case NODE_TYPE_AGENT:
|
||||
case NODE_TYPE_AVATAR_MIXER:
|
||||
channel = BandwidthMeter::AVATARS;
|
||||
break;
|
||||
case AGENT_TYPE_VOXEL_SERVER:
|
||||
case NODE_TYPE_VOXEL_SERVER:
|
||||
channel = BandwidthMeter::VOXELS;
|
||||
break;
|
||||
default:
|
||||
|
@ -508,7 +508,7 @@ void Application::sendVoxelServerAddScene() {
|
|||
char message[100];
|
||||
sprintf(message,"%c%s",'Z',"add scene");
|
||||
int messageSize = strlen(message) + 1;
|
||||
broadcastToAgents((unsigned char*)message, messageSize, AGENT_TYPE_VOXEL_SERVER);
|
||||
broadcastToNodes((unsigned char*)message, messageSize, NODE_TYPE_VOXEL_SERVER);
|
||||
}
|
||||
|
||||
void Application::keyPressEvent(QKeyEvent* event) {
|
||||
|
@ -881,13 +881,13 @@ void Application::wheelEvent(QWheelEvent* event) {
|
|||
|
||||
void sendPingPackets() {
|
||||
|
||||
char agentTypesOfInterest[] = {AGENT_TYPE_VOXEL_SERVER, AGENT_TYPE_AUDIO_MIXER, AGENT_TYPE_AVATAR_MIXER};
|
||||
char nodeTypesOfInterest[] = {NODE_TYPE_VOXEL_SERVER, NODE_TYPE_AUDIO_MIXER, NODE_TYPE_AVATAR_MIXER};
|
||||
long long currentTime = usecTimestampNow();
|
||||
char pingPacket[1 + sizeof(currentTime)];
|
||||
pingPacket[0] = PACKET_HEADER_PING;
|
||||
|
||||
memcpy(&pingPacket[1], ¤tTime, sizeof(currentTime));
|
||||
AgentList::getInstance()->broadcastToAgents((unsigned char*)pingPacket, 1 + sizeof(currentTime), agentTypesOfInterest, 3);
|
||||
NodeList::getInstance()->broadcastToNodes((unsigned char*)pingPacket, 1 + sizeof(currentTime), nodeTypesOfInterest, 3);
|
||||
|
||||
}
|
||||
|
||||
|
@ -913,8 +913,8 @@ void Application::timer() {
|
|||
_serialHeadSensor.pair();
|
||||
}
|
||||
|
||||
// ask the agent list to check in with the domain server
|
||||
AgentList::getInstance()->sendDomainServerCheckIn();
|
||||
// ask the node list to check in with the domain server
|
||||
NodeList::getInstance()->sendDomainServerCheckIn();
|
||||
}
|
||||
|
||||
static glm::vec3 getFaceVector(BoxFace face) {
|
||||
|
@ -970,9 +970,9 @@ void Application::terminate() {
|
|||
}
|
||||
|
||||
void Application::sendAvatarVoxelURLMessage(const QUrl& url) {
|
||||
uint16_t ownerID = AgentList::getInstance()->getOwnerID();
|
||||
uint16_t ownerID = NodeList::getInstance()->getOwnerID();
|
||||
|
||||
if (ownerID == UNKNOWN_AGENT_ID) {
|
||||
if (ownerID == UNKNOWN_NODE_ID) {
|
||||
return; // we don't yet know who we are
|
||||
}
|
||||
QByteArray message;
|
||||
|
@ -980,7 +980,7 @@ void Application::sendAvatarVoxelURLMessage(const QUrl& url) {
|
|||
message.append((const char*)&ownerID, sizeof(ownerID));
|
||||
message.append(url.toEncoded());
|
||||
|
||||
broadcastToAgents((unsigned char*)message.data(), message.size(), AGENT_TYPE_AVATAR_MIXER);
|
||||
broadcastToNodes((unsigned char*)message.data(), message.size(), NODE_TYPE_AVATAR_MIXER);
|
||||
}
|
||||
|
||||
void Application::processAvatarVoxelURLMessage(unsigned char *packetData, size_t dataBytes) {
|
||||
|
@ -988,17 +988,17 @@ void Application::processAvatarVoxelURLMessage(unsigned char *packetData, size_t
|
|||
packetData++;
|
||||
dataBytes--;
|
||||
|
||||
// read the agent id
|
||||
uint16_t agentID = *(uint16_t*)packetData;
|
||||
packetData += sizeof(agentID);
|
||||
dataBytes -= sizeof(agentID);
|
||||
// read the node id
|
||||
uint16_t nodeID = *(uint16_t*)packetData;
|
||||
packetData += sizeof(nodeID);
|
||||
dataBytes -= sizeof(nodeID);
|
||||
|
||||
// make sure the agent exists
|
||||
Agent* agent = AgentList::getInstance()->agentWithID(agentID);
|
||||
if (!agent || !agent->getLinkedData()) {
|
||||
// make sure the node exists
|
||||
Node* node = NodeList::getInstance()->nodeWithID(nodeID);
|
||||
if (!node || !node->getLinkedData()) {
|
||||
return;
|
||||
}
|
||||
Avatar* avatar = static_cast<Avatar*>(agent->getLinkedData());
|
||||
Avatar* avatar = static_cast<Avatar*>(node->getLinkedData());
|
||||
if (!avatar->isInitialized()) {
|
||||
return; // wait until initialized
|
||||
}
|
||||
|
@ -1213,7 +1213,7 @@ void Application::sendVoxelEditMessage(PACKET_HEADER header, VoxelDetail& detail
|
|||
int sizeOut;
|
||||
|
||||
if (createVoxelEditMessage(header, 0, 1, &detail, bufferOut, sizeOut)){
|
||||
Application::broadcastToAgents(bufferOut, sizeOut, AGENT_TYPE_VOXEL_SERVER);
|
||||
Application::broadcastToNodes(bufferOut, sizeOut, NODE_TYPE_VOXEL_SERVER);
|
||||
delete[] bufferOut;
|
||||
}
|
||||
}
|
||||
|
@ -1294,7 +1294,7 @@ bool Application::sendVoxelsOperation(VoxelNode* node, void* extraData) {
|
|||
|
||||
// if we have room don't have room in the buffer, then send the previously generated message first
|
||||
if (args->bufferInUse + codeAndColorLength > MAXIMUM_EDIT_VOXEL_MESSAGE_SIZE) {
|
||||
broadcastToAgents(args->messageBuffer, args->bufferInUse, AGENT_TYPE_VOXEL_SERVER);
|
||||
broadcastToNodes(args->messageBuffer, args->bufferInUse, NODE_TYPE_VOXEL_SERVER);
|
||||
args->bufferInUse = sizeof(PACKET_HEADER_SET_VOXEL_DESTRUCTIVE) + sizeof(unsigned short int); // reset
|
||||
}
|
||||
|
||||
|
@ -1375,7 +1375,7 @@ void Application::importVoxels() {
|
|||
|
||||
// If we have voxels left in the packet, then send the packet
|
||||
if (args.bufferInUse > (sizeof(PACKET_HEADER_SET_VOXEL_DESTRUCTIVE) + sizeof(unsigned short int))) {
|
||||
broadcastToAgents(args.messageBuffer, args.bufferInUse, AGENT_TYPE_VOXEL_SERVER);
|
||||
broadcastToNodes(args.messageBuffer, args.bufferInUse, NODE_TYPE_VOXEL_SERVER);
|
||||
}
|
||||
|
||||
if (calculatedOctCode) {
|
||||
|
@ -1427,7 +1427,7 @@ void Application::pasteVoxels() {
|
|||
|
||||
// If we have voxels left in the packet, then send the packet
|
||||
if (args.bufferInUse > (sizeof(PACKET_HEADER_SET_VOXEL_DESTRUCTIVE) + sizeof(unsigned short int))) {
|
||||
broadcastToAgents(args.messageBuffer, args.bufferInUse, AGENT_TYPE_VOXEL_SERVER);
|
||||
broadcastToNodes(args.messageBuffer, args.bufferInUse, NODE_TYPE_VOXEL_SERVER);
|
||||
}
|
||||
|
||||
if (calculatedOctCode) {
|
||||
|
@ -1820,7 +1820,7 @@ void Application::update(float deltaTime) {
|
|||
|
||||
// Update transmitter
|
||||
|
||||
// Sample hardware, update view frustum if needed, and send avatar data to mixer/agents
|
||||
// Sample hardware, update view frustum if needed, and send avatar data to mixer/nodes
|
||||
updateAvatar(deltaTime);
|
||||
|
||||
// read incoming packets from network
|
||||
|
@ -1829,11 +1829,11 @@ void Application::update(float deltaTime) {
|
|||
}
|
||||
|
||||
//loop through all the other avatars and simulate them...
|
||||
AgentList* agentList = AgentList::getInstance();
|
||||
agentList->lock();
|
||||
for(AgentList::iterator agent = agentList->begin(); agent != agentList->end(); agent++) {
|
||||
if (agent->getLinkedData() != NULL) {
|
||||
Avatar *avatar = (Avatar *)agent->getLinkedData();
|
||||
NodeList* nodeList = NodeList::getInstance();
|
||||
nodeList->lock();
|
||||
for(NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
|
||||
if (node->getLinkedData() != NULL) {
|
||||
Avatar *avatar = (Avatar *)node->getLinkedData();
|
||||
if (!avatar->isInitialized()) {
|
||||
avatar->init();
|
||||
}
|
||||
|
@ -1841,7 +1841,7 @@ void Application::update(float deltaTime) {
|
|||
avatar->setMouseRay(mouseRayOrigin, mouseRayDirection);
|
||||
}
|
||||
}
|
||||
agentList->unlock();
|
||||
nodeList->unlock();
|
||||
|
||||
// Simulate myself
|
||||
if (_gravityUse->isChecked()) {
|
||||
|
@ -1968,19 +1968,19 @@ void Application::updateAvatar(float deltaTime) {
|
|||
_myAvatar.setCameraNearClip(_viewFrustum.getNearClip());
|
||||
_myAvatar.setCameraFarClip(_viewFrustum.getFarClip());
|
||||
|
||||
AgentList* agentList = AgentList::getInstance();
|
||||
if (agentList->getOwnerID() != UNKNOWN_AGENT_ID) {
|
||||
NodeList* nodeList = NodeList::getInstance();
|
||||
if (nodeList->getOwnerID() != UNKNOWN_NODE_ID) {
|
||||
// if I know my ID, send head/hand data to the avatar mixer and voxel server
|
||||
unsigned char broadcastString[200];
|
||||
unsigned char* endOfBroadcastStringWrite = broadcastString;
|
||||
|
||||
*(endOfBroadcastStringWrite++) = PACKET_HEADER_HEAD_DATA;
|
||||
endOfBroadcastStringWrite += packAgentId(endOfBroadcastStringWrite, agentList->getOwnerID());
|
||||
endOfBroadcastStringWrite += packNodeId(endOfBroadcastStringWrite, nodeList->getOwnerID());
|
||||
|
||||
endOfBroadcastStringWrite += _myAvatar.getBroadcastData(endOfBroadcastStringWrite);
|
||||
|
||||
broadcastToAgents(broadcastString, endOfBroadcastStringWrite - broadcastString, AGENT_TYPE_VOXEL_SERVER);
|
||||
broadcastToAgents(broadcastString, endOfBroadcastStringWrite - broadcastString, AGENT_TYPE_AVATAR_MIXER);
|
||||
broadcastToNodes(broadcastString, endOfBroadcastStringWrite - broadcastString, NODE_TYPE_VOXEL_SERVER);
|
||||
broadcastToNodes(broadcastString, endOfBroadcastStringWrite - broadcastString, NODE_TYPE_AVATAR_MIXER);
|
||||
|
||||
// once in a while, send my voxel url
|
||||
const float AVATAR_VOXEL_URL_SEND_INTERVAL = 1.0f; // seconds
|
||||
|
@ -1989,7 +1989,7 @@ void Application::updateAvatar(float deltaTime) {
|
|||
}
|
||||
}
|
||||
|
||||
// If I'm in paint mode, send a voxel out to VOXEL server agents.
|
||||
// If I'm in paint mode, send a voxel out to VOXEL server nodes.
|
||||
if (_paintOn) {
|
||||
|
||||
glm::vec3 avatarPos = _myAvatar.getPosition();
|
||||
|
@ -2294,12 +2294,12 @@ void Application::displaySide(Camera& whichCamera) {
|
|||
}
|
||||
|
||||
if (_renderAvatarsOn->isChecked()) {
|
||||
// Render avatars of other agents
|
||||
AgentList* agentList = AgentList::getInstance();
|
||||
agentList->lock();
|
||||
for (AgentList::iterator agent = agentList->begin(); agent != agentList->end(); agent++) {
|
||||
if (agent->getLinkedData() != NULL && agent->getType() == AGENT_TYPE_AVATAR) {
|
||||
Avatar *avatar = (Avatar *)agent->getLinkedData();
|
||||
// Render avatars of other nodes
|
||||
NodeList* nodeList = NodeList::getInstance();
|
||||
nodeList->lock();
|
||||
for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
|
||||
if (node->getLinkedData() != NULL && node->getType() == NODE_TYPE_AGENT) {
|
||||
Avatar *avatar = (Avatar *)node->getLinkedData();
|
||||
if (!avatar->isInitialized()) {
|
||||
avatar->init();
|
||||
}
|
||||
|
@ -2307,7 +2307,7 @@ void Application::displaySide(Camera& whichCamera) {
|
|||
avatar->setDisplayingLookatVectors(_renderLookatOn->isChecked());
|
||||
}
|
||||
}
|
||||
agentList->unlock();
|
||||
nodeList->unlock();
|
||||
|
||||
// Render my own Avatar
|
||||
if (_myCamera.getMode() == CAMERA_MODE_MIRROR) {
|
||||
|
@ -2390,17 +2390,17 @@ void Application::displayOverlay() {
|
|||
|
||||
// Stats at upper right of screen about who domain server is telling us about
|
||||
glPointSize(1.0f);
|
||||
char agents[100];
|
||||
char nodes[100];
|
||||
|
||||
AgentList* agentList = AgentList::getInstance();
|
||||
NodeList* nodeList = NodeList::getInstance();
|
||||
int totalAvatars = 0, totalServers = 0;
|
||||
|
||||
for (AgentList::iterator agent = agentList->begin(); agent != agentList->end(); agent++) {
|
||||
agent->getType() == AGENT_TYPE_AVATAR ? totalAvatars++ : totalServers++;
|
||||
for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
|
||||
node->getType() == NODE_TYPE_AGENT ? totalAvatars++ : totalServers++;
|
||||
}
|
||||
|
||||
sprintf(agents, "Servers: %d, Avatars: %d\n", totalServers, totalAvatars);
|
||||
drawtext(_glWidget->width() - 150, 20, 0.10, 0, 1.0, 0, agents, 1, 0, 0);
|
||||
sprintf(nodes, "Servers: %d, Avatars: %d\n", totalServers, totalAvatars);
|
||||
drawtext(_glWidget->width() - 150, 20, 0.10, 0, 1.0, 0, nodes, 1, 0, 0);
|
||||
|
||||
if (_paintOn) {
|
||||
|
||||
|
@ -2428,14 +2428,14 @@ void Application::displayStats() {
|
|||
if (_testPing->isChecked()) {
|
||||
int pingAudio = 0, pingAvatar = 0, pingVoxel = 0;
|
||||
|
||||
AgentList *agentList = AgentList::getInstance();
|
||||
Agent *audioMixerAgent = agentList->soloAgentOfType(AGENT_TYPE_AUDIO_MIXER);
|
||||
Agent *avatarMixerAgent = agentList->soloAgentOfType(AGENT_TYPE_AVATAR_MIXER);
|
||||
Agent *voxelServerAgent = agentList->soloAgentOfType(AGENT_TYPE_VOXEL_SERVER);
|
||||
NodeList *nodeList = NodeList::getInstance();
|
||||
Node *audioMixerNode = nodeList->soloNodeOfType(NODE_TYPE_AUDIO_MIXER);
|
||||
Node *avatarMixerNode = nodeList->soloNodeOfType(NODE_TYPE_AVATAR_MIXER);
|
||||
Node *voxelServerNode = nodeList->soloNodeOfType(NODE_TYPE_VOXEL_SERVER);
|
||||
|
||||
pingAudio = audioMixerAgent ? audioMixerAgent->getPingMs() : 0;
|
||||
pingAvatar = avatarMixerAgent ? avatarMixerAgent->getPingMs() : 0;
|
||||
pingVoxel = voxelServerAgent ? voxelServerAgent->getPingMs() : 0;
|
||||
pingAudio = audioMixerNode ? audioMixerNode->getPingMs() : 0;
|
||||
pingAvatar = avatarMixerNode ? avatarMixerNode->getPingMs() : 0;
|
||||
pingVoxel = voxelServerNode ? voxelServerNode->getPingMs() : 0;
|
||||
|
||||
char pingStats[200];
|
||||
sprintf(pingStats, "Ping audio/avatar/voxel: %d / %d / %d ", pingAudio, pingAvatar, pingVoxel);
|
||||
|
@ -2470,7 +2470,7 @@ void Application::displayStats() {
|
|||
voxelStats << "Voxels Bits per Colored: " << voxelsBytesPerColored * 8;
|
||||
drawtext(10, statsVerticalOffset + 310, 0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str());
|
||||
|
||||
Agent *avatarMixer = AgentList::getInstance()->soloAgentOfType(AGENT_TYPE_AVATAR_MIXER);
|
||||
Node *avatarMixer = NodeList::getInstance()->soloNodeOfType(NODE_TYPE_AVATAR_MIXER);
|
||||
char avatarMixerStats[200];
|
||||
|
||||
if (avatarMixer) {
|
||||
|
@ -2841,13 +2841,13 @@ QAction* Application::checkedVoxelModeAction() const {
|
|||
return 0;
|
||||
}
|
||||
|
||||
void Application::attachNewHeadToAgent(Agent* newAgent) {
|
||||
if (newAgent->getLinkedData() == NULL) {
|
||||
newAgent->setLinkedData(new Avatar(newAgent));
|
||||
void Application::attachNewHeadToNode(Node* newNode) {
|
||||
if (newNode->getLinkedData() == NULL) {
|
||||
newNode->setLinkedData(new Avatar(newNode));
|
||||
}
|
||||
}
|
||||
|
||||
// Receive packets from other agents/servers and decide what to do with them!
|
||||
// Receive packets from other nodes/servers and decide what to do with them!
|
||||
void* Application::networkReceive(void* args) {
|
||||
sockaddr senderAddress;
|
||||
ssize_t bytesReceived;
|
||||
|
@ -2860,7 +2860,7 @@ void* Application::networkReceive(void* args) {
|
|||
app->_wantToKillLocalVoxels = false;
|
||||
}
|
||||
|
||||
if (AgentList::getInstance()->getAgentSocket()->receive(&senderAddress, app->_incomingPacket, &bytesReceived)) {
|
||||
if (NodeList::getInstance()->getNodeSocket()->receive(&senderAddress, app->_incomingPacket, &bytesReceived)) {
|
||||
app->_packetCount++;
|
||||
app->_bytesCount += bytesReceived;
|
||||
|
||||
|
@ -2883,7 +2883,7 @@ void* Application::networkReceive(void* args) {
|
|||
app->_environment.parseData(&senderAddress, app->_incomingPacket, bytesReceived);
|
||||
break;
|
||||
case PACKET_HEADER_BULK_AVATAR_DATA:
|
||||
AgentList::getInstance()->processBulkAgentData(&senderAddress,
|
||||
NodeList::getInstance()->processBulkNodeData(&senderAddress,
|
||||
app->_incomingPacket,
|
||||
bytesReceived);
|
||||
getInstance()->_bandwidthMeter.inputStream(BandwidthMeter::AVATARS).updateValue(bytesReceived);
|
||||
|
@ -2892,7 +2892,7 @@ void* Application::networkReceive(void* args) {
|
|||
processAvatarVoxelURLMessage(app->_incomingPacket, bytesReceived);
|
||||
break;
|
||||
default:
|
||||
AgentList::getInstance()->processAgentData(&senderAddress, app->_incomingPacket, bytesReceived);
|
||||
NodeList::getInstance()->processNodeData(&senderAddress, app->_incomingPacket, bytesReceived);
|
||||
break;
|
||||
}
|
||||
} else if (!app->_enableNetworkThread) {
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
#include <QTouchEvent>
|
||||
#include <QList>
|
||||
|
||||
#include <AgentList.h>
|
||||
#include <NodeList.h>
|
||||
|
||||
#include "BandwidthMeter.h"
|
||||
#include "ui/BandwidthDialog.h"
|
||||
|
@ -50,7 +50,7 @@ class QNetworkAccessManager;
|
|||
class QSettings;
|
||||
class QWheelEvent;
|
||||
|
||||
class Agent;
|
||||
class Node;
|
||||
class ProgramObject;
|
||||
|
||||
class Application : public QApplication {
|
||||
|
@ -152,7 +152,7 @@ private slots:
|
|||
void runTests();
|
||||
private:
|
||||
|
||||
static void broadcastToAgents(unsigned char* data, size_t bytes, const char type);
|
||||
static void broadcastToNodes(unsigned char* data, size_t bytes, const char type);
|
||||
static void sendVoxelServerAddScene();
|
||||
static bool sendVoxelsOperation(VoxelNode* node, void* extraData);
|
||||
static void sendAvatarVoxelURLMessage(const QUrl& url);
|
||||
|
@ -190,7 +190,7 @@ private:
|
|||
|
||||
QAction* checkedVoxelModeAction() const;
|
||||
|
||||
static void attachNewHeadToAgent(Agent *newAgent);
|
||||
static void attachNewHeadToNode(Node *newNode);
|
||||
static void* networkReceive(void* args);
|
||||
|
||||
// methodes handling menu settings
|
||||
|
|
|
@ -17,8 +17,8 @@
|
|||
#include <UDPSocket.h>
|
||||
#include <SharedUtil.h>
|
||||
#include <PacketHeaders.h>
|
||||
#include <AgentList.h>
|
||||
#include <AgentTypes.h>
|
||||
#include <NodeList.h>
|
||||
#include <NodeTypes.h>
|
||||
#include <AngleUtil.h>
|
||||
|
||||
#include "Application.h"
|
||||
|
@ -46,7 +46,7 @@ static const short JITTER_BUFFER_SAMPLES = JITTER_BUFFER_LENGTH_MSECS *
|
|||
|
||||
static const float AUDIO_CALLBACK_MSECS = (float)BUFFER_LENGTH_SAMPLES_PER_CHANNEL / (float)SAMPLE_RATE * 1000.0;
|
||||
|
||||
static const int AGENT_LOOPBACK_MODIFIER = 307;
|
||||
static const int NODE_LOOPBACK_MODIFIER = 307;
|
||||
|
||||
// Speex preprocessor and echo canceller adaption
|
||||
static const int AEC_N_CHANNELS_MIC = 1; // Number of microphone channels
|
||||
|
@ -72,14 +72,14 @@ static const int PING_BUFFER_OFFSET = BUFFER_LENGTH_SAMPLES_PER_CHANNEL - PING
|
|||
|
||||
inline void Audio::performIO(int16_t* inputLeft, int16_t* outputLeft, int16_t* outputRight) {
|
||||
|
||||
AgentList* agentList = AgentList::getInstance();
|
||||
NodeList* nodeList = NodeList::getInstance();
|
||||
Application* interface = Application::getInstance();
|
||||
Avatar* interfaceAvatar = interface->getAvatar();
|
||||
|
||||
// Add Procedural effects to input samples
|
||||
addProceduralSounds(inputLeft, BUFFER_LENGTH_SAMPLES_PER_CHANNEL);
|
||||
|
||||
if (agentList && inputLeft) {
|
||||
if (nodeList && inputLeft) {
|
||||
|
||||
// Measure the loudness of the signal from the microphone and store in audio object
|
||||
float loudness = 0;
|
||||
|
@ -93,7 +93,7 @@ inline void Audio::performIO(int16_t* inputLeft, int16_t* outputLeft, int16_t* o
|
|||
// add input (@microphone) data to the scope
|
||||
_scope->addSamples(0, inputLeft, BUFFER_LENGTH_SAMPLES_PER_CHANNEL);
|
||||
|
||||
Agent* audioMixer = agentList->soloAgentOfType(AGENT_TYPE_AUDIO_MIXER);
|
||||
Node* audioMixer = nodeList->soloNodeOfType(NODE_TYPE_AUDIO_MIXER);
|
||||
|
||||
if (audioMixer) {
|
||||
glm::vec3 headPosition = interfaceAvatar->getHeadJointPosition();
|
||||
|
@ -120,7 +120,7 @@ inline void Audio::performIO(int16_t* inputLeft, int16_t* outputLeft, int16_t* o
|
|||
|
||||
// copy the audio data to the last BUFFER_LENGTH_BYTES bytes of the data packet
|
||||
memcpy(currentPacketPtr, inputLeft, BUFFER_LENGTH_BYTES_PER_CHANNEL);
|
||||
agentList->getAgentSocket()->send(audioMixer->getActiveSocket(),
|
||||
nodeList->getNodeSocket()->send(audioMixer->getActiveSocket(),
|
||||
dataPacket,
|
||||
BUFFER_LENGTH_BYTES_PER_CHANNEL + leadingBytes);
|
||||
|
||||
|
|
|
@ -17,8 +17,8 @@
|
|||
#include "Head.h"
|
||||
#include "Log.h"
|
||||
#include "ui/TextRenderer.h"
|
||||
#include <AgentList.h>
|
||||
#include <AgentTypes.h>
|
||||
#include <NodeList.h>
|
||||
#include <NodeTypes.h>
|
||||
#include <PacketHeaders.h>
|
||||
#include <OculusManager.h>
|
||||
|
||||
|
@ -61,8 +61,8 @@ bool usingBigSphereCollisionTest = true;
|
|||
float chatMessageScale = 0.0015;
|
||||
float chatMessageHeight = 0.20;
|
||||
|
||||
Avatar::Avatar(Agent* owningAgent) :
|
||||
AvatarData(owningAgent),
|
||||
Avatar::Avatar(Node* owningNode) :
|
||||
AvatarData(owningNode),
|
||||
_initialized(false),
|
||||
_head(this),
|
||||
_hand(this),
|
||||
|
@ -725,10 +725,10 @@ void Avatar::updateHandMovementAndTouching(float deltaTime) {
|
|||
_interactingOther = NULL;
|
||||
|
||||
//loop through all the other avatars for potential interactions...
|
||||
AgentList* agentList = AgentList::getInstance();
|
||||
for (AgentList::iterator agent = agentList->begin(); agent != agentList->end(); agent++) {
|
||||
if (agent->getLinkedData() && agent->getType() == AGENT_TYPE_AVATAR) {
|
||||
Avatar *otherAvatar = (Avatar *)agent->getLinkedData();
|
||||
NodeList* nodeList = NodeList::getInstance();
|
||||
for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
|
||||
if (node->getLinkedData() && node->getType() == NODE_TYPE_AGENT) {
|
||||
Avatar *otherAvatar = (Avatar *)node->getLinkedData();
|
||||
|
||||
// test whether shoulders are close enough to allow for reaching to touch hands
|
||||
glm::vec3 v(_position - otherAvatar->_position);
|
||||
|
@ -905,10 +905,10 @@ void Avatar::updateAvatarCollisions(float deltaTime) {
|
|||
_distanceToNearestAvatar = std::numeric_limits<float>::max();
|
||||
|
||||
// loop through all the other avatars for potential interactions...
|
||||
AgentList* agentList = AgentList::getInstance();
|
||||
for (AgentList::iterator agent = agentList->begin(); agent != agentList->end(); agent++) {
|
||||
if (agent->getLinkedData() && agent->getType() == AGENT_TYPE_AVATAR) {
|
||||
Avatar *otherAvatar = (Avatar *)agent->getLinkedData();
|
||||
NodeList* nodeList = NodeList::getInstance();
|
||||
for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
|
||||
if (node->getLinkedData() && node->getType() == NODE_TYPE_AGENT) {
|
||||
Avatar *otherAvatar = (Avatar *)node->getLinkedData();
|
||||
|
||||
// check if the bounding spheres of the two avatars are colliding
|
||||
glm::vec3 vectorBetweenBoundingSpheres(_position - otherAvatar->_position);
|
||||
|
|
|
@ -80,7 +80,7 @@ enum AvatarMode
|
|||
|
||||
class Avatar : public AvatarData {
|
||||
public:
|
||||
Avatar(Agent* owningAgent = NULL);
|
||||
Avatar(Node* owningNode = NULL);
|
||||
~Avatar();
|
||||
|
||||
void init();
|
||||
|
@ -107,7 +107,7 @@ public:
|
|||
|
||||
//getters
|
||||
bool isInitialized () const { return _initialized;}
|
||||
bool isMyAvatar () const { return _owningAgent == NULL; }
|
||||
bool isMyAvatar () const { return _owningNode == NULL; }
|
||||
const Skeleton& getSkeleton () const { return _skeleton;}
|
||||
float getHeadYawRate () const { return _head.yawRate;}
|
||||
float getBodyYaw () const { return _bodyYaw;}
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
#include <QImage>
|
||||
|
||||
#include <AgentList.h>
|
||||
#include <NodeList.h>
|
||||
|
||||
#include "Application.h"
|
||||
#include "Avatar.h"
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
#include <QImage>
|
||||
|
||||
#include <AgentList.h>
|
||||
#include <NodeList.h>
|
||||
|
||||
#include "Application.h"
|
||||
#include "Avatar.h"
|
||||
|
@ -270,16 +270,16 @@ void Head::render(bool lookingInMirror, float alpha) {
|
|||
|
||||
|
||||
void Head::createMohawk() {
|
||||
uint16_t agentId = 0;
|
||||
if (_owningAvatar->getOwningAgent()) {
|
||||
agentId = _owningAvatar->getOwningAgent()->getAgentID();
|
||||
uint16_t nodeId = 0;
|
||||
if (_owningAvatar->getOwningNode()) {
|
||||
nodeId = _owningAvatar->getOwningNode()->getNodeID();
|
||||
} else {
|
||||
agentId = AgentList::getInstance()->getOwnerID();
|
||||
if (agentId == UNKNOWN_AGENT_ID) {
|
||||
nodeId = NodeList::getInstance()->getOwnerID();
|
||||
if (nodeId == UNKNOWN_NODE_ID) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
srand(agentId);
|
||||
srand(nodeId);
|
||||
float height = 0.08f + randFloat() * 0.05f;
|
||||
float variance = 0.03 + randFloat() * 0.03f;
|
||||
const float RAD_PER_TRIANGLE = (2.3f + randFloat() * 0.2f) / (float)MOHAWK_TRIANGLES;
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <AgentList.h>
|
||||
#include <NodeList.h>
|
||||
|
||||
#include "PairingHandler.h"
|
||||
|
||||
|
@ -18,8 +18,8 @@ const char PAIRING_SERVER_HOSTNAME[] = "pairing.highfidelity.io";
|
|||
const int PAIRING_SERVER_PORT = 7247;
|
||||
|
||||
void PairingHandler::sendPairRequest() {
|
||||
// grab the agent socket from the AgentList singleton
|
||||
UDPSocket *agentSocket = AgentList::getInstance()->getAgentSocket();
|
||||
// grab the node socket from the NodeList singleton
|
||||
UDPSocket *nodeSocket = NodeList::getInstance()->getNodeSocket();
|
||||
|
||||
// prepare the pairing request packet
|
||||
|
||||
|
@ -32,7 +32,7 @@ void PairingHandler::sendPairRequest() {
|
|||
(localAddress >> 8) & 0xFF,
|
||||
(localAddress >> 16) & 0xFF,
|
||||
(localAddress >> 24) & 0xFF,
|
||||
AGENT_SOCKET_LISTEN_PORT);
|
||||
NODE_SOCKET_LISTEN_PORT);
|
||||
|
||||
sockaddr_in pairingServerSocket;
|
||||
|
||||
|
@ -44,5 +44,5 @@ void PairingHandler::sendPairRequest() {
|
|||
pairingServerSocket.sin_port = htons(PAIRING_SERVER_PORT);
|
||||
|
||||
// send the pair request to the pairing server
|
||||
agentSocket->send((sockaddr*) &pairingServerSocket, pairPacket, strlen(pairPacket));
|
||||
nodeSocket->send((sockaddr*) &pairingServerSocket, pairPacket, strlen(pairPacket));
|
||||
}
|
||||
|
|
|
@ -47,7 +47,7 @@ GLubyte identityIndices[] = { 0,2,1, 0,3,2, // Z-
|
|||
4,5,6, 4,6,7 }; // Z+
|
||||
|
||||
VoxelSystem::VoxelSystem(float treeScale, int maxVoxels) :
|
||||
AgentData(NULL), _treeScale(treeScale), _maxVoxels(maxVoxels) {
|
||||
NodeData(NULL), _treeScale(treeScale), _maxVoxels(maxVoxels) {
|
||||
_voxelsInReadArrays = _voxelsInWriteArrays = _voxelsUpdated = 0;
|
||||
_writeRenderFullVBO = true;
|
||||
_readRenderFullVBO = true;
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
#include <glm/glm.hpp>
|
||||
#include <SharedUtil.h>
|
||||
#include <UDPSocket.h>
|
||||
#include <AgentData.h>
|
||||
#include <NodeData.h>
|
||||
#include <VoxelTree.h>
|
||||
#include <ViewFrustum.h>
|
||||
#include "Camera.h"
|
||||
|
@ -24,7 +24,7 @@ class ProgramObject;
|
|||
|
||||
const int NUM_CHILDREN = 8;
|
||||
|
||||
class VoxelSystem : public AgentData {
|
||||
class VoxelSystem : public NodeData {
|
||||
public:
|
||||
VoxelSystem(float treeScale = TREE_SCALE, int maxVoxels = MAX_VOXELS_PER_SYSTEM);
|
||||
~VoxelSystem();
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
// discover the appropriate audio, voxel, and avatar servers to contact.
|
||||
// Right now, the default domain server is "highfidelity.below92.com"
|
||||
// You can change the domain server to use your own by editing the
|
||||
// DOMAIN_HOSTNAME or DOMAIN_IP strings in the file AgentList.cpp
|
||||
// DOMAIN_HOSTNAME or DOMAIN_IP strings in the file NodeList.cpp
|
||||
//
|
||||
//
|
||||
// Welcome Aboard!
|
||||
|
|
|
@ -9,9 +9,9 @@
|
|||
#include <sys/time.h>
|
||||
|
||||
#include "SharedUtil.h"
|
||||
#include "AgentList.h"
|
||||
#include "AgentTypes.h"
|
||||
#include "Agent.h"
|
||||
#include "NodeList.h"
|
||||
#include "NodeTypes.h"
|
||||
#include "Node.h"
|
||||
#include "PacketHeaders.h"
|
||||
|
||||
#include "AudioInjectionManager.h"
|
||||
|
@ -51,14 +51,14 @@ void AudioInjectionManager::setDestinationSocket(sockaddr& destinationSocket) {
|
|||
void* AudioInjectionManager::injectAudioViaThread(void* args) {
|
||||
AudioInjector* injector = (AudioInjector*) args;
|
||||
|
||||
// if we don't have an injectorSocket then grab the one from the agent list
|
||||
// if we don't have an injectorSocket then grab the one from the node list
|
||||
if (!_injectorSocket) {
|
||||
_injectorSocket = AgentList::getInstance()->getAgentSocket();
|
||||
_injectorSocket = NodeList::getInstance()->getNodeSocket();
|
||||
}
|
||||
|
||||
// if we don't have an explicit destination socket then pull active socket for current audio mixer from agent list
|
||||
// if we don't have an explicit destination socket then pull active socket for current audio mixer from node list
|
||||
if (!_isDestinationSocketExplicit) {
|
||||
Agent* audioMixer = AgentList::getInstance()->soloAgentOfType(AGENT_TYPE_AUDIO_MIXER);
|
||||
Node* audioMixer = NodeList::getInstance()->soloNodeOfType(NODE_TYPE_AUDIO_MIXER);
|
||||
if (audioMixer) {
|
||||
_destinationSocket = *audioMixer->getActiveSocket();
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
#include "AudioRingBuffer.h"
|
||||
|
||||
AudioRingBuffer::AudioRingBuffer(bool isStereo) :
|
||||
AgentData(NULL),
|
||||
NodeData(NULL),
|
||||
_endOfLastWrite(NULL),
|
||||
_isStarted(false),
|
||||
_isStereo(isStereo)
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#include "AgentData.h"
|
||||
#include "NodeData.h"
|
||||
|
||||
const float SAMPLE_RATE = 22050.0;
|
||||
|
||||
|
@ -25,7 +25,7 @@ const int BUFFER_LENGTH_SAMPLES_PER_CHANNEL = BUFFER_LENGTH_BYTES_PER_CHANNEL /
|
|||
const short RING_BUFFER_LENGTH_FRAMES = 20;
|
||||
const short RING_BUFFER_LENGTH_SAMPLES = RING_BUFFER_LENGTH_FRAMES * BUFFER_LENGTH_SAMPLES_PER_CHANNEL;
|
||||
|
||||
class AudioRingBuffer : public AgentData {
|
||||
class AudioRingBuffer : public NodeData {
|
||||
public:
|
||||
AudioRingBuffer(bool isStereo);
|
||||
~AudioRingBuffer();
|
||||
|
|
|
@ -18,8 +18,8 @@
|
|||
|
||||
using namespace std;
|
||||
|
||||
AvatarData::AvatarData(Agent* owningAgent) :
|
||||
AgentData(owningAgent),
|
||||
AvatarData::AvatarData(Node* owningNode) :
|
||||
NodeData(owningNode),
|
||||
_handPosition(0,0,0),
|
||||
_bodyYaw(-90.0),
|
||||
_bodyPitch(0.0),
|
||||
|
@ -155,7 +155,7 @@ int AvatarData::getBroadcastData(unsigned char* destinationBuffer) {
|
|||
return destinationBuffer - bufferStart;
|
||||
}
|
||||
|
||||
// called on the other agents - assigns it to my views of the others
|
||||
// called on the other nodes - assigns it to my views of the others
|
||||
int AvatarData::parseData(unsigned char* sourceBuffer, int numBytes) {
|
||||
|
||||
// lazily allocate memory for HeadData in case we're not an Avatar instance
|
||||
|
@ -173,7 +173,7 @@ int AvatarData::parseData(unsigned char* sourceBuffer, int numBytes) {
|
|||
|
||||
unsigned char* startPosition = sourceBuffer;
|
||||
|
||||
// push past the agent ID
|
||||
// push past the node ID
|
||||
sourceBuffer += + sizeof(uint16_t);
|
||||
|
||||
// Body world position
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
|
||||
#include <AgentData.h>
|
||||
#include <NodeData.h>
|
||||
#include "HeadData.h"
|
||||
#include "HandData.h"
|
||||
|
||||
|
@ -36,9 +36,9 @@ enum KeyState
|
|||
DELETE_KEY_DOWN
|
||||
};
|
||||
|
||||
class AvatarData : public AgentData {
|
||||
class AvatarData : public NodeData {
|
||||
public:
|
||||
AvatarData(Agent* owningAgent = NULL);
|
||||
AvatarData(Node* owningNode = NULL);
|
||||
~AvatarData();
|
||||
|
||||
const glm::vec3& getPosition() const { return _position; }
|
||||
|
|
|
@ -1,153 +0,0 @@
|
|||
//
|
||||
// Agent.cpp
|
||||
// hifi
|
||||
//
|
||||
// Created by Stephen Birarda on 2/15/13.
|
||||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#include "stdio.h"
|
||||
|
||||
#include <pthread.h>
|
||||
#include "Agent.h"
|
||||
#include "AgentTypes.h"
|
||||
#include <cstring>
|
||||
#include "Log.h"
|
||||
#include "UDPSocket.h"
|
||||
#include "SharedUtil.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "Syssocket.h"
|
||||
#else
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
int unpackAgentId(unsigned char* packedData, uint16_t* agentId) {
|
||||
memcpy(agentId, packedData, sizeof(uint16_t));
|
||||
return sizeof(uint16_t);
|
||||
}
|
||||
|
||||
int packAgentId(unsigned char* packStore, uint16_t agentId) {
|
||||
memcpy(packStore, &agentId, sizeof(uint16_t));
|
||||
return sizeof(uint16_t);
|
||||
}
|
||||
|
||||
Agent::Agent(sockaddr* publicSocket, sockaddr* localSocket, char type, uint16_t agentID) :
|
||||
_type(type),
|
||||
_agentID(agentID),
|
||||
_wakeMicrostamp(usecTimestampNow()),
|
||||
_lastHeardMicrostamp(usecTimestampNow()),
|
||||
_activeSocket(NULL),
|
||||
_bytesReceivedMovingAverage(NULL),
|
||||
_linkedData(NULL),
|
||||
_isAlive(true)
|
||||
{
|
||||
if (publicSocket) {
|
||||
_publicSocket = new sockaddr(*publicSocket);
|
||||
} else {
|
||||
_publicSocket = NULL;
|
||||
}
|
||||
|
||||
if (localSocket) {
|
||||
_localSocket = new sockaddr(*localSocket);
|
||||
} else {
|
||||
_localSocket = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
Agent::~Agent() {
|
||||
delete _publicSocket;
|
||||
delete _localSocket;
|
||||
delete _linkedData;
|
||||
delete _bytesReceivedMovingAverage;
|
||||
}
|
||||
|
||||
// Names of Agent Types
|
||||
const char* AGENT_TYPE_NAME_DOMAIN = "Domain";
|
||||
const char* AGENT_TYPE_NAME_VOXEL_SERVER = "Voxel Server";
|
||||
const char* AGENT_TYPE_NAME_INTERFACE = "Client Interface";
|
||||
const char* AGENT_TYPE_NAME_AUDIO_MIXER = "Audio Mixer";
|
||||
const char* AGENT_TYPE_NAME_AVATAR_MIXER = "Avatar Mixer";
|
||||
const char* AGENT_TYPE_NAME_AUDIO_INJECTOR = "Audio Injector";
|
||||
const char* AGENT_TYPE_NAME_ANIMATION_SERVER = "Animation Server";
|
||||
const char* AGENT_TYPE_NAME_UNKNOWN = "Unknown";
|
||||
|
||||
const char* Agent::getTypeName() const {
|
||||
switch (this->_type) {
|
||||
case AGENT_TYPE_DOMAIN:
|
||||
return AGENT_TYPE_NAME_DOMAIN;
|
||||
case AGENT_TYPE_VOXEL_SERVER:
|
||||
return AGENT_TYPE_NAME_VOXEL_SERVER;
|
||||
case AGENT_TYPE_AVATAR:
|
||||
return AGENT_TYPE_NAME_INTERFACE;
|
||||
case AGENT_TYPE_AUDIO_MIXER:
|
||||
return AGENT_TYPE_NAME_AUDIO_MIXER;
|
||||
case AGENT_TYPE_AVATAR_MIXER:
|
||||
return AGENT_TYPE_NAME_AVATAR_MIXER;
|
||||
case AGENT_TYPE_AUDIO_INJECTOR:
|
||||
return AGENT_TYPE_NAME_AUDIO_INJECTOR;
|
||||
case AGENT_TYPE_ANIMATION_SERVER:
|
||||
return AGENT_TYPE_NAME_ANIMATION_SERVER;
|
||||
default:
|
||||
return AGENT_TYPE_NAME_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
void Agent::activateLocalSocket() {
|
||||
_activeSocket = _localSocket;
|
||||
}
|
||||
|
||||
void Agent::activatePublicSocket() {
|
||||
_activeSocket = _publicSocket;
|
||||
}
|
||||
|
||||
bool Agent::operator==(const Agent& otherAgent) {
|
||||
return matches(otherAgent._publicSocket, otherAgent._localSocket, otherAgent._type);
|
||||
}
|
||||
|
||||
bool Agent::matches(sockaddr* otherPublicSocket, sockaddr* otherLocalSocket, char otherAgentType) {
|
||||
// checks if two agent objects are the same agent (same type + local + public address)
|
||||
return _type == otherAgentType
|
||||
&& socketMatch(_publicSocket, otherPublicSocket)
|
||||
&& socketMatch(_localSocket, otherLocalSocket);
|
||||
}
|
||||
|
||||
void Agent::recordBytesReceived(int bytesReceived) {
|
||||
if (_bytesReceivedMovingAverage == NULL) {
|
||||
_bytesReceivedMovingAverage = new SimpleMovingAverage(100);
|
||||
}
|
||||
|
||||
_bytesReceivedMovingAverage->updateAverage((float) bytesReceived);
|
||||
}
|
||||
|
||||
float Agent::getAveragePacketsPerSecond() {
|
||||
if (_bytesReceivedMovingAverage) {
|
||||
return (1 / _bytesReceivedMovingAverage->getEventDeltaAverage());
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
float Agent::getAverageKilobitsPerSecond() {
|
||||
if (_bytesReceivedMovingAverage) {
|
||||
return (_bytesReceivedMovingAverage->getAverageSampleValuePerSecond() * (8.0f / 1000));
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void Agent::printLog(Agent const& agent) {
|
||||
|
||||
char publicAddressBuffer[16] = {'\0'};
|
||||
unsigned short publicAddressPort = loadBufferWithSocketInfo(publicAddressBuffer, agent._publicSocket);
|
||||
|
||||
//char localAddressBuffer[16] = {'\0'};
|
||||
//unsigned short localAddressPort = loadBufferWithSocketInfo(localAddressBuffer, agent.localSocket);
|
||||
|
||||
::printLog("# %d %s (%c) @ %s:%d\n",
|
||||
agent._agentID,
|
||||
agent.getTypeName(),
|
||||
agent._type,
|
||||
publicAddressBuffer,
|
||||
publicAddressPort);
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
//
|
||||
// AgentData.cpp
|
||||
// hifi
|
||||
//
|
||||
// Created by Stephen Birarda on 2/19/13.
|
||||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#include "AgentData.h"
|
||||
|
||||
AgentData::AgentData(Agent* owningAgent) :
|
||||
_owningAgent(owningAgent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
AgentData::~AgentData() {}
|
|
@ -1,556 +0,0 @@
|
|||
//
|
||||
// AgentList.cpp
|
||||
// hifi
|
||||
//
|
||||
// Created by Stephen Birarda on 2/15/13.
|
||||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#include <pthread.h>
|
||||
#include <cstring>
|
||||
#include <cstdlib>
|
||||
#include <cstdio>
|
||||
|
||||
#include "AgentList.h"
|
||||
#include "AgentTypes.h"
|
||||
#include "PacketHeaders.h"
|
||||
#include "SharedUtil.h"
|
||||
#include "Log.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "Syssocket.h"
|
||||
#else
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
const char SOLO_AGENT_TYPES[3] = {
|
||||
AGENT_TYPE_AVATAR_MIXER,
|
||||
AGENT_TYPE_AUDIO_MIXER,
|
||||
AGENT_TYPE_VOXEL_SERVER
|
||||
};
|
||||
|
||||
char DOMAIN_HOSTNAME[] = "highfidelity.below92.com";
|
||||
char DOMAIN_IP[100] = ""; // IP Address will be re-set by lookup on startup
|
||||
const int DOMAINSERVER_PORT = 40102;
|
||||
|
||||
bool silentAgentThreadStopFlag = false;
|
||||
bool pingUnknownAgentThreadStopFlag = false;
|
||||
|
||||
AgentList* AgentList::_sharedInstance = NULL;
|
||||
|
||||
AgentList* AgentList::createInstance(char ownerType, unsigned int socketListenPort) {
|
||||
if (!_sharedInstance) {
|
||||
_sharedInstance = new AgentList(ownerType, socketListenPort);
|
||||
} else {
|
||||
printLog("AgentList createInstance called with existing instance.\n");
|
||||
}
|
||||
|
||||
return _sharedInstance;
|
||||
}
|
||||
|
||||
AgentList* AgentList::getInstance() {
|
||||
if (!_sharedInstance) {
|
||||
printLog("AgentList getInstance called before call to createInstance. Returning NULL pointer.\n");
|
||||
}
|
||||
|
||||
return _sharedInstance;
|
||||
}
|
||||
|
||||
AgentList::AgentList(char newOwnerType, unsigned int newSocketListenPort) :
|
||||
_agentBuckets(),
|
||||
_numAgents(0),
|
||||
_agentSocket(newSocketListenPort),
|
||||
_ownerType(newOwnerType),
|
||||
_agentTypesOfInterest(NULL),
|
||||
_ownerID(UNKNOWN_AGENT_ID),
|
||||
_lastAgentID(0) {
|
||||
pthread_mutex_init(&mutex, 0);
|
||||
}
|
||||
|
||||
AgentList::~AgentList() {
|
||||
delete _agentTypesOfInterest;
|
||||
|
||||
// stop the spawned threads, if they were started
|
||||
stopSilentAgentRemovalThread();
|
||||
stopPingUnknownAgentsThread();
|
||||
|
||||
pthread_mutex_destroy(&mutex);
|
||||
}
|
||||
|
||||
void AgentList::timePingReply(sockaddr *agentAddress, unsigned char *packetData) {
|
||||
for(AgentList::iterator agent = begin(); agent != end(); agent++) {
|
||||
if (socketMatch(agent->getPublicSocket(), agentAddress) ||
|
||||
socketMatch(agent->getLocalSocket(), agentAddress)) {
|
||||
int pingTime = usecTimestampNow() - *(long long *)(packetData + 1);
|
||||
agent->setPingMs(pingTime / 1000);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AgentList::processAgentData(sockaddr *senderAddress, unsigned char *packetData, size_t dataBytes) {
|
||||
switch (((char *)packetData)[0]) {
|
||||
case PACKET_HEADER_DOMAIN: {
|
||||
processDomainServerList(packetData, dataBytes);
|
||||
break;
|
||||
}
|
||||
case PACKET_HEADER_PING: {
|
||||
char pingPacket[dataBytes];
|
||||
memcpy(pingPacket, packetData, dataBytes);
|
||||
pingPacket[0] = PACKET_HEADER_PING_REPLY;
|
||||
_agentSocket.send(senderAddress, pingPacket, dataBytes);
|
||||
break;
|
||||
}
|
||||
case PACKET_HEADER_PING_REPLY: {
|
||||
timePingReply(senderAddress, packetData);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AgentList::processBulkAgentData(sockaddr *senderAddress, unsigned char *packetData, int numTotalBytes) {
|
||||
lock();
|
||||
|
||||
// find the avatar mixer in our agent list and update the lastRecvTime from it
|
||||
Agent* bulkSendAgent = agentWithAddress(senderAddress);
|
||||
|
||||
if (bulkSendAgent) {
|
||||
bulkSendAgent->setLastHeardMicrostamp(usecTimestampNow());
|
||||
bulkSendAgent->recordBytesReceived(numTotalBytes);
|
||||
}
|
||||
|
||||
unsigned char *startPosition = packetData;
|
||||
unsigned char *currentPosition = startPosition + 1;
|
||||
unsigned char packetHolder[numTotalBytes];
|
||||
|
||||
packetHolder[0] = PACKET_HEADER_HEAD_DATA;
|
||||
|
||||
uint16_t agentID = -1;
|
||||
|
||||
while ((currentPosition - startPosition) < numTotalBytes) {
|
||||
unpackAgentId(currentPosition, &agentID);
|
||||
memcpy(packetHolder + 1, currentPosition, numTotalBytes - (currentPosition - startPosition));
|
||||
|
||||
Agent* matchingAgent = agentWithID(agentID);
|
||||
|
||||
if (!matchingAgent) {
|
||||
// we're missing this agent, we need to add it to the list
|
||||
matchingAgent = addOrUpdateAgent(NULL, NULL, AGENT_TYPE_AVATAR, agentID);
|
||||
}
|
||||
|
||||
currentPosition += updateAgentWithData(matchingAgent,
|
||||
packetHolder,
|
||||
numTotalBytes - (currentPosition - startPosition));
|
||||
}
|
||||
|
||||
unlock();
|
||||
}
|
||||
|
||||
int AgentList::updateAgentWithData(sockaddr *senderAddress, unsigned char *packetData, size_t dataBytes) {
|
||||
// find the agent by the sockaddr
|
||||
Agent* matchingAgent = agentWithAddress(senderAddress);
|
||||
|
||||
if (matchingAgent) {
|
||||
return updateAgentWithData(matchingAgent, packetData, dataBytes);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int AgentList::updateAgentWithData(Agent *agent, unsigned char *packetData, int dataBytes) {
|
||||
agent->setLastHeardMicrostamp(usecTimestampNow());
|
||||
|
||||
if (agent->getActiveSocket()) {
|
||||
agent->recordBytesReceived(dataBytes);
|
||||
}
|
||||
|
||||
if (!agent->getLinkedData() && linkedDataCreateCallback) {
|
||||
linkedDataCreateCallback(agent);
|
||||
}
|
||||
|
||||
return agent->getLinkedData()->parseData(packetData, dataBytes);
|
||||
}
|
||||
|
||||
Agent* AgentList::agentWithAddress(sockaddr *senderAddress) {
|
||||
for(AgentList::iterator agent = begin(); agent != end(); agent++) {
|
||||
if (agent->getActiveSocket() && socketMatch(agent->getActiveSocket(), senderAddress)) {
|
||||
return &(*agent);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Agent* AgentList::agentWithID(uint16_t agentID) {
|
||||
for(AgentList::iterator agent = begin(); agent != end(); agent++) {
|
||||
if (agent->getAgentID() == agentID) {
|
||||
return &(*agent);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int AgentList::getNumAliveAgents() const {
|
||||
int numAliveAgents = 0;
|
||||
|
||||
for (AgentList::iterator agent = begin(); agent != end(); agent++) {
|
||||
if (agent->isAlive()) {
|
||||
++numAliveAgents;
|
||||
}
|
||||
}
|
||||
|
||||
return numAliveAgents;
|
||||
}
|
||||
|
||||
void AgentList::setAgentTypesOfInterest(const char* agentTypesOfInterest, int numAgentTypesOfInterest) {
|
||||
delete _agentTypesOfInterest;
|
||||
|
||||
_agentTypesOfInterest = new char[numAgentTypesOfInterest + sizeof(char)];
|
||||
memcpy(_agentTypesOfInterest, agentTypesOfInterest, numAgentTypesOfInterest);
|
||||
_agentTypesOfInterest[numAgentTypesOfInterest] = '\0';
|
||||
}
|
||||
|
||||
void AgentList::sendDomainServerCheckIn() {
|
||||
static bool printedDomainServerIP = false;
|
||||
// Lookup the IP address of the domain server if we need to
|
||||
if (atoi(DOMAIN_IP) == 0) {
|
||||
struct hostent* pHostInfo;
|
||||
if ((pHostInfo = gethostbyname(DOMAIN_HOSTNAME)) != NULL) {
|
||||
sockaddr_in tempAddress;
|
||||
memcpy(&tempAddress.sin_addr, pHostInfo->h_addr_list[0], pHostInfo->h_length);
|
||||
strcpy(DOMAIN_IP, inet_ntoa(tempAddress.sin_addr));
|
||||
printLog("Domain Server: %s \n", DOMAIN_HOSTNAME);
|
||||
} else {
|
||||
printLog("Failed domain server lookup\n");
|
||||
}
|
||||
} else if (!printedDomainServerIP) {
|
||||
printLog("Domain Server IP: %s\n", DOMAIN_IP);
|
||||
printedDomainServerIP = true;
|
||||
}
|
||||
|
||||
// construct the DS check in packet if we need to
|
||||
static unsigned char* checkInPacket = NULL;
|
||||
static int checkInPacketSize;
|
||||
|
||||
if (!checkInPacket) {
|
||||
int numBytesAgentsOfInterest = _agentTypesOfInterest ? strlen((char*) _agentTypesOfInterest) : 0;
|
||||
|
||||
// check in packet has header, agent type, port, IP, agent types of interest, null termination
|
||||
int numPacketBytes = sizeof(PACKET_HEADER) + sizeof(AGENT_TYPE) + sizeof(uint16_t) + (sizeof(char) * 4) +
|
||||
numBytesAgentsOfInterest + sizeof(unsigned char);
|
||||
|
||||
checkInPacket = new unsigned char[numPacketBytes];
|
||||
unsigned char* packetPosition = checkInPacket;
|
||||
|
||||
*(packetPosition++) = (memchr(SOLO_AGENT_TYPES, _ownerType, sizeof(SOLO_AGENT_TYPES)))
|
||||
? PACKET_HEADER_DOMAIN_REPORT_FOR_DUTY
|
||||
: PACKET_HEADER_DOMAIN_LIST_REQUEST;
|
||||
*(packetPosition++) = _ownerType;
|
||||
|
||||
packetPosition += packSocket(checkInPacket + sizeof(PACKET_HEADER) + sizeof(AGENT_TYPE),
|
||||
getLocalAddress(),
|
||||
htons(_agentSocket.getListeningPort()));
|
||||
|
||||
// add the number of bytes for agent types of interest
|
||||
*(packetPosition++) = numBytesAgentsOfInterest;
|
||||
|
||||
// copy over the bytes for agent types of interest, if required
|
||||
if (numBytesAgentsOfInterest > 0) {
|
||||
memcpy(packetPosition,
|
||||
_agentTypesOfInterest,
|
||||
numBytesAgentsOfInterest);
|
||||
packetPosition += numBytesAgentsOfInterest;
|
||||
}
|
||||
|
||||
checkInPacketSize = packetPosition - checkInPacket;
|
||||
}
|
||||
|
||||
_agentSocket.send(DOMAIN_IP, DOMAINSERVER_PORT, checkInPacket, checkInPacketSize);
|
||||
}
|
||||
|
||||
int AgentList::processDomainServerList(unsigned char *packetData, size_t dataBytes) {
|
||||
int readAgents = 0;
|
||||
|
||||
char agentType;
|
||||
uint16_t agentId;
|
||||
|
||||
// assumes only IPv4 addresses
|
||||
sockaddr_in agentPublicSocket;
|
||||
agentPublicSocket.sin_family = AF_INET;
|
||||
sockaddr_in agentLocalSocket;
|
||||
agentLocalSocket.sin_family = AF_INET;
|
||||
|
||||
unsigned char *readPtr = packetData + 1;
|
||||
unsigned char *startPtr = packetData;
|
||||
|
||||
while((readPtr - startPtr) < dataBytes - sizeof(uint16_t)) {
|
||||
agentType = *readPtr++;
|
||||
readPtr += unpackAgentId(readPtr, (uint16_t *)&agentId);
|
||||
readPtr += unpackSocket(readPtr, (sockaddr *)&agentPublicSocket);
|
||||
readPtr += unpackSocket(readPtr, (sockaddr *)&agentLocalSocket);
|
||||
|
||||
addOrUpdateAgent((sockaddr *)&agentPublicSocket, (sockaddr *)&agentLocalSocket, agentType, agentId);
|
||||
}
|
||||
|
||||
// read out our ID from the packet
|
||||
unpackAgentId(readPtr, &_ownerID);
|
||||
|
||||
return readAgents;
|
||||
}
|
||||
|
||||
Agent* AgentList::addOrUpdateAgent(sockaddr* publicSocket, sockaddr* localSocket, char agentType, uint16_t agentId) {
|
||||
AgentList::iterator agent = end();
|
||||
|
||||
if (publicSocket) {
|
||||
for (agent = begin(); agent != end(); agent++) {
|
||||
if (agent->matches(publicSocket, localSocket, agentType)) {
|
||||
// we already have this agent, stop checking
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (agent == end()) {
|
||||
// we didn't have this agent, so add them
|
||||
Agent* newAgent = new Agent(publicSocket, localSocket, agentType, agentId);
|
||||
|
||||
if (socketMatch(publicSocket, localSocket)) {
|
||||
// likely debugging scenario with two agents on local network
|
||||
// set the agent active right away
|
||||
newAgent->activatePublicSocket();
|
||||
}
|
||||
|
||||
if (newAgent->getType() == AGENT_TYPE_VOXEL_SERVER ||
|
||||
newAgent->getType() == AGENT_TYPE_AVATAR_MIXER ||
|
||||
newAgent->getType() == AGENT_TYPE_AUDIO_MIXER) {
|
||||
// this is currently the cheat we use to talk directly to our test servers on EC2
|
||||
// to be removed when we have a proper identification strategy
|
||||
newAgent->activatePublicSocket();
|
||||
}
|
||||
|
||||
addAgentToList(newAgent);
|
||||
|
||||
return newAgent;
|
||||
} else {
|
||||
|
||||
if (agent->getType() == AGENT_TYPE_AUDIO_MIXER ||
|
||||
agent->getType() == AGENT_TYPE_VOXEL_SERVER) {
|
||||
// until the Audio class also uses our agentList, we need to update
|
||||
// the lastRecvTimeUsecs for the audio mixer so it doesn't get killed and re-added continously
|
||||
agent->setLastHeardMicrostamp(usecTimestampNow());
|
||||
}
|
||||
|
||||
// we had this agent already, do nothing for now
|
||||
return &*agent;
|
||||
}
|
||||
}
|
||||
|
||||
void AgentList::addAgentToList(Agent* newAgent) {
|
||||
// find the correct array to add this agent to
|
||||
int bucketIndex = _numAgents / AGENTS_PER_BUCKET;
|
||||
|
||||
if (!_agentBuckets[bucketIndex]) {
|
||||
_agentBuckets[bucketIndex] = new Agent*[AGENTS_PER_BUCKET]();
|
||||
}
|
||||
|
||||
_agentBuckets[bucketIndex][_numAgents % AGENTS_PER_BUCKET] = newAgent;
|
||||
|
||||
++_numAgents;
|
||||
|
||||
printLog("Added ");
|
||||
Agent::printLog(*newAgent);
|
||||
}
|
||||
|
||||
unsigned AgentList::broadcastToAgents(unsigned char *broadcastData, size_t dataBytes, const char* agentTypes, int numAgentTypes) {
|
||||
unsigned n = 0;
|
||||
for(AgentList::iterator agent = begin(); agent != end(); agent++) {
|
||||
// only send to the AgentTypes we are asked to send to.
|
||||
if (agent->getActiveSocket() != NULL && memchr(agentTypes, agent->getType(), numAgentTypes)) {
|
||||
// we know which socket is good for this agent, send there
|
||||
_agentSocket.send(agent->getActiveSocket(), broadcastData, dataBytes);
|
||||
++n;
|
||||
}
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
void AgentList::handlePingReply(sockaddr *agentAddress) {
|
||||
for(AgentList::iterator agent = begin(); agent != end(); agent++) {
|
||||
// check both the public and local addresses for each agent to see if we find a match
|
||||
// prioritize the private address so that we prune erroneous local matches
|
||||
if (socketMatch(agent->getPublicSocket(), agentAddress)) {
|
||||
agent->activatePublicSocket();
|
||||
break;
|
||||
} else if (socketMatch(agent->getLocalSocket(), agentAddress)) {
|
||||
agent->activateLocalSocket();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Agent* AgentList::soloAgentOfType(char agentType) {
|
||||
if (memchr(SOLO_AGENT_TYPES, agentType, sizeof(SOLO_AGENT_TYPES)) != NULL) {
|
||||
for(AgentList::iterator agent = begin(); agent != end(); agent++) {
|
||||
if (agent->getType() == agentType) {
|
||||
return &(*agent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *pingUnknownAgents(void *args) {
|
||||
|
||||
AgentList* agentList = (AgentList*) args;
|
||||
const int PING_INTERVAL_USECS = 1 * 1000000;
|
||||
|
||||
timeval lastSend;
|
||||
|
||||
while (!pingUnknownAgentThreadStopFlag) {
|
||||
gettimeofday(&lastSend, NULL);
|
||||
|
||||
for(AgentList::iterator agent = agentList->begin();
|
||||
agent != agentList->end();
|
||||
agent++) {
|
||||
if (!agent->getActiveSocket() && agent->getPublicSocket() && agent->getLocalSocket()) {
|
||||
// ping both of the sockets for the agent so we can figure out
|
||||
// which socket we can use
|
||||
agentList->getAgentSocket()->send(agent->getPublicSocket(), &PACKET_HEADER_PING, 1);
|
||||
agentList->getAgentSocket()->send(agent->getLocalSocket(), &PACKET_HEADER_PING, 1);
|
||||
}
|
||||
}
|
||||
|
||||
long long usecToSleep = PING_INTERVAL_USECS - (usecTimestampNow() - usecTimestamp(&lastSend));
|
||||
|
||||
if (usecToSleep > 0) {
|
||||
usleep(usecToSleep);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void AgentList::startPingUnknownAgentsThread() {
|
||||
pthread_create(&pingUnknownAgentsThread, NULL, pingUnknownAgents, (void *)this);
|
||||
}
|
||||
|
||||
void AgentList::stopPingUnknownAgentsThread() {
|
||||
pingUnknownAgentThreadStopFlag = true;
|
||||
pthread_join(pingUnknownAgentsThread, NULL);
|
||||
}
|
||||
|
||||
void *removeSilentAgents(void *args) {
|
||||
AgentList* agentList = (AgentList*) args;
|
||||
long long checkTimeUSecs, sleepTime;
|
||||
|
||||
while (!silentAgentThreadStopFlag) {
|
||||
checkTimeUSecs = usecTimestampNow();
|
||||
|
||||
for(AgentList::iterator agent = agentList->begin(); agent != agentList->end(); ++agent) {
|
||||
|
||||
if ((checkTimeUSecs - agent->getLastHeardMicrostamp()) > AGENT_SILENCE_THRESHOLD_USECS
|
||||
&& agent->getType() != AGENT_TYPE_VOXEL_SERVER) {
|
||||
|
||||
printLog("Killed ");
|
||||
Agent::printLog(*agent);
|
||||
|
||||
agent->setAlive(false);
|
||||
}
|
||||
}
|
||||
|
||||
sleepTime = AGENT_SILENCE_THRESHOLD_USECS - (usecTimestampNow() - checkTimeUSecs);
|
||||
#ifdef _WIN32
|
||||
Sleep( static_cast<int>(1000.0f*sleepTime) );
|
||||
#else
|
||||
usleep(sleepTime);
|
||||
#endif
|
||||
}
|
||||
|
||||
pthread_exit(0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void AgentList::startSilentAgentRemovalThread() {
|
||||
pthread_create(&removeSilentAgentsThread, NULL, removeSilentAgents, (void*) this);
|
||||
}
|
||||
|
||||
void AgentList::stopSilentAgentRemovalThread() {
|
||||
silentAgentThreadStopFlag = true;
|
||||
pthread_join(removeSilentAgentsThread, NULL);
|
||||
}
|
||||
|
||||
AgentList::iterator AgentList::begin() const {
|
||||
Agent** agentBucket = NULL;
|
||||
|
||||
for (int i = 0; i < _numAgents; i++) {
|
||||
if (i % AGENTS_PER_BUCKET == 0) {
|
||||
agentBucket = _agentBuckets[i / AGENTS_PER_BUCKET];
|
||||
}
|
||||
|
||||
if (agentBucket[i % AGENTS_PER_BUCKET]->isAlive()) {
|
||||
return AgentListIterator(this, i);
|
||||
}
|
||||
}
|
||||
|
||||
// there's no alive agent to start from - return the end
|
||||
return end();
|
||||
}
|
||||
|
||||
AgentList::iterator AgentList::end() const {
|
||||
return AgentListIterator(this, _numAgents);
|
||||
}
|
||||
|
||||
AgentListIterator::AgentListIterator(const AgentList* agentList, int agentIndex) :
|
||||
_agentIndex(agentIndex) {
|
||||
_agentList = agentList;
|
||||
}
|
||||
|
||||
AgentListIterator& AgentListIterator::operator=(const AgentListIterator& otherValue) {
|
||||
_agentList = otherValue._agentList;
|
||||
_agentIndex = otherValue._agentIndex;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool AgentListIterator::operator==(const AgentListIterator &otherValue) {
|
||||
return _agentIndex == otherValue._agentIndex;
|
||||
}
|
||||
|
||||
bool AgentListIterator::operator!=(const AgentListIterator &otherValue) {
|
||||
return !(*this == otherValue);
|
||||
}
|
||||
|
||||
Agent& AgentListIterator::operator*() {
|
||||
Agent** agentBucket = _agentList->_agentBuckets[_agentIndex / AGENTS_PER_BUCKET];
|
||||
return *agentBucket[_agentIndex % AGENTS_PER_BUCKET];
|
||||
}
|
||||
|
||||
Agent* AgentListIterator::operator->() {
|
||||
Agent** agentBucket = _agentList->_agentBuckets[_agentIndex / AGENTS_PER_BUCKET];
|
||||
return agentBucket[_agentIndex % AGENTS_PER_BUCKET];
|
||||
}
|
||||
|
||||
AgentListIterator& AgentListIterator::operator++() {
|
||||
skipDeadAndStopIncrement();
|
||||
return *this;
|
||||
}
|
||||
|
||||
AgentList::iterator AgentListIterator::operator++(int) {
|
||||
AgentListIterator newIterator = AgentListIterator(*this);
|
||||
skipDeadAndStopIncrement();
|
||||
return newIterator;
|
||||
}
|
||||
|
||||
void AgentListIterator::skipDeadAndStopIncrement() {
|
||||
while (_agentIndex != _agentList->_numAgents) {
|
||||
++_agentIndex;
|
||||
|
||||
if (_agentIndex == _agentList->_numAgents) {
|
||||
break;
|
||||
} else if ((*(*this)).isAlive()) {
|
||||
// skip over the dead agents
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,147 +0,0 @@
|
|||
//
|
||||
// AgentList.h
|
||||
// hifi
|
||||
//
|
||||
// Created by Stephen Birarda on 2/15/13.
|
||||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef __hifi__AgentList__
|
||||
#define __hifi__AgentList__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <iterator>
|
||||
|
||||
#include "Agent.h"
|
||||
#include "UDPSocket.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "pthread.h"
|
||||
#endif
|
||||
|
||||
const int MAX_NUM_AGENTS = 10000;
|
||||
const int AGENTS_PER_BUCKET = 100;
|
||||
|
||||
const int MAX_PACKET_SIZE = 1500;
|
||||
const unsigned int AGENT_SOCKET_LISTEN_PORT = 40103;
|
||||
|
||||
const int AGENT_SILENCE_THRESHOLD_USECS = 2 * 1000000;
|
||||
const int DOMAIN_SERVER_CHECK_IN_USECS = 1 * 1000000;
|
||||
|
||||
extern const char SOLO_AGENT_TYPES[3];
|
||||
|
||||
extern char DOMAIN_HOSTNAME[];
|
||||
extern char DOMAIN_IP[100]; // IP Address will be re-set by lookup on startup
|
||||
extern const int DOMAINSERVER_PORT;
|
||||
|
||||
const int UNKNOWN_AGENT_ID = -1;
|
||||
|
||||
class AgentListIterator;
|
||||
|
||||
class AgentList {
|
||||
public:
|
||||
static AgentList* createInstance(char ownerType, unsigned int socketListenPort = AGENT_SOCKET_LISTEN_PORT);
|
||||
static AgentList* getInstance();
|
||||
|
||||
typedef AgentListIterator iterator;
|
||||
|
||||
AgentListIterator begin() const;
|
||||
AgentListIterator end() const;
|
||||
|
||||
char getOwnerType() const { return _ownerType; }
|
||||
|
||||
uint16_t getLastAgentID() const { return _lastAgentID; }
|
||||
void increaseAgentID() { ++_lastAgentID; }
|
||||
|
||||
uint16_t getOwnerID() const { return _ownerID; }
|
||||
void setOwnerID(uint16_t ownerID) { _ownerID = ownerID; }
|
||||
|
||||
UDPSocket* getAgentSocket() { return &_agentSocket; }
|
||||
|
||||
unsigned int getSocketListenPort() const { return _agentSocket.getListeningPort(); };
|
||||
|
||||
void(*linkedDataCreateCallback)(Agent *);
|
||||
|
||||
int size() { return _numAgents; }
|
||||
int getNumAliveAgents() const;
|
||||
|
||||
void lock() { pthread_mutex_lock(&mutex); }
|
||||
void unlock() { pthread_mutex_unlock(&mutex); }
|
||||
|
||||
void setAgentTypesOfInterest(const char* agentTypesOfInterest, int numAgentTypesOfInterest);
|
||||
void sendDomainServerCheckIn();
|
||||
int processDomainServerList(unsigned char *packetData, size_t dataBytes);
|
||||
|
||||
Agent* agentWithAddress(sockaddr *senderAddress);
|
||||
Agent* agentWithID(uint16_t agentID);
|
||||
|
||||
Agent* addOrUpdateAgent(sockaddr* publicSocket, sockaddr* localSocket, char agentType, uint16_t agentId);
|
||||
|
||||
void processAgentData(sockaddr *senderAddress, unsigned char *packetData, size_t dataBytes);
|
||||
void processBulkAgentData(sockaddr *senderAddress, unsigned char *packetData, int numTotalBytes);
|
||||
|
||||
int updateAgentWithData(sockaddr *senderAddress, unsigned char *packetData, size_t dataBytes);
|
||||
int updateAgentWithData(Agent *agent, unsigned char *packetData, int dataBytes);
|
||||
|
||||
unsigned broadcastToAgents(unsigned char *broadcastData, size_t dataBytes, const char* agentTypes, int numAgentTypes);
|
||||
|
||||
Agent* soloAgentOfType(char agentType);
|
||||
|
||||
void startSilentAgentRemovalThread();
|
||||
void stopSilentAgentRemovalThread();
|
||||
void startPingUnknownAgentsThread();
|
||||
void stopPingUnknownAgentsThread();
|
||||
|
||||
friend class AgentListIterator;
|
||||
private:
|
||||
static AgentList* _sharedInstance;
|
||||
|
||||
AgentList(char ownerType, unsigned int socketListenPort);
|
||||
~AgentList();
|
||||
AgentList(AgentList const&); // Don't implement, needed to avoid copies of singleton
|
||||
void operator=(AgentList const&); // Don't implement, needed to avoid copies of singleton
|
||||
|
||||
void addAgentToList(Agent* newAgent);
|
||||
|
||||
Agent** _agentBuckets[MAX_NUM_AGENTS / AGENTS_PER_BUCKET];
|
||||
int _numAgents;
|
||||
UDPSocket _agentSocket;
|
||||
char _ownerType;
|
||||
char* _agentTypesOfInterest;
|
||||
unsigned int _socketListenPort;
|
||||
uint16_t _ownerID;
|
||||
uint16_t _lastAgentID;
|
||||
pthread_t removeSilentAgentsThread;
|
||||
pthread_t checkInWithDomainServerThread;
|
||||
pthread_t pingUnknownAgentsThread;
|
||||
pthread_mutex_t mutex;
|
||||
|
||||
void handlePingReply(sockaddr *agentAddress);
|
||||
void timePingReply(sockaddr *agentAddress, unsigned char *packetData);
|
||||
};
|
||||
|
||||
class AgentListIterator : public std::iterator<std::input_iterator_tag, Agent> {
|
||||
public:
|
||||
AgentListIterator(const AgentList* agentList, int agentIndex);
|
||||
~AgentListIterator() {};
|
||||
|
||||
int getAgentIndex() { return _agentIndex; };
|
||||
|
||||
AgentListIterator& operator=(const AgentListIterator& otherValue);
|
||||
|
||||
bool operator==(const AgentListIterator& otherValue);
|
||||
bool operator!= (const AgentListIterator& otherValue);
|
||||
|
||||
Agent& operator*();
|
||||
Agent* operator->();
|
||||
|
||||
AgentListIterator& operator++();
|
||||
AgentListIterator operator++(int);
|
||||
private:
|
||||
void skipDeadAndStopIncrement();
|
||||
|
||||
const AgentList* _agentList;
|
||||
int _agentIndex;
|
||||
};
|
||||
|
||||
#endif /* defined(__hifi__AgentList__) */
|
|
@ -1,28 +0,0 @@
|
|||
//
|
||||
// AgentTypes.h
|
||||
// hifi
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 2013/04/09
|
||||
// Copyright (c) 2013 HighFidelity, Inc. All rights reserved.
|
||||
//
|
||||
// Single byte/character Agent Types used to identify various agents in the system.
|
||||
// For example, an agent whose is 'V' is always a voxel server.
|
||||
|
||||
#ifndef hifi_AgentTypes_h
|
||||
#define hifi_AgentTypes_h
|
||||
|
||||
// NOTE: If you add a new AGENT_TYPE_XXX then you also should add a new AGENT_TYPE_NAME_XXX and a new "case" to the
|
||||
// switch statement in Agent.cpp specifically Agent::getTypeName().
|
||||
// If you don't then it will make things harder on your co-developers in debugging because the Agent
|
||||
// class won't know the name and will report it as "Unknown".
|
||||
|
||||
typedef char AGENT_TYPE;
|
||||
const AGENT_TYPE AGENT_TYPE_DOMAIN = 'D';
|
||||
const AGENT_TYPE AGENT_TYPE_VOXEL_SERVER = 'V';
|
||||
const AGENT_TYPE AGENT_TYPE_AVATAR = 'I';
|
||||
const AGENT_TYPE AGENT_TYPE_AUDIO_MIXER = 'M';
|
||||
const AGENT_TYPE AGENT_TYPE_AVATAR_MIXER = 'W';
|
||||
const AGENT_TYPE AGENT_TYPE_AUDIO_INJECTOR = 'A';
|
||||
const AGENT_TYPE AGENT_TYPE_ANIMATION_SERVER = 'a';
|
||||
|
||||
#endif
|
|
@ -11,7 +11,7 @@
|
|||
#include <netdb.h>
|
||||
|
||||
#include "SharedUtil.h"
|
||||
#include "AgentList.h"
|
||||
#include "NodeList.h"
|
||||
|
||||
#include "Logstash.h"
|
||||
|
||||
|
@ -52,9 +52,9 @@ void Logstash::stashValue(char statType, const char* key, float value) {
|
|||
// send it to 4 decimal places
|
||||
int numPacketBytes = sprintf(logstashPacket, "%c %s %.4f", statType, key, value);
|
||||
|
||||
AgentList *agentList = AgentList::getInstance();
|
||||
NodeList *nodeList = NodeList::getInstance();
|
||||
|
||||
if (agentList) {
|
||||
agentList->getAgentSocket()->send(socket(), logstashPacket, numPacketBytes);
|
||||
if (nodeList) {
|
||||
nodeList->getNodeSocket()->send(socket(), logstashPacket, numPacketBytes);
|
||||
}
|
||||
}
|
153
libraries/shared/src/Node.cpp
Normal file
153
libraries/shared/src/Node.cpp
Normal file
|
@ -0,0 +1,153 @@
|
|||
//
|
||||
// Node.cpp
|
||||
// hifi
|
||||
//
|
||||
// Created by Stephen Birarda on 2/15/13.
|
||||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#include "stdio.h"
|
||||
|
||||
#include <pthread.h>
|
||||
#include "Node.h"
|
||||
#include "NodeTypes.h"
|
||||
#include <cstring>
|
||||
#include "Log.h"
|
||||
#include "UDPSocket.h"
|
||||
#include "SharedUtil.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "Syssocket.h"
|
||||
#else
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
int unpackNodeId(unsigned char* packedData, uint16_t* nodeId) {
|
||||
memcpy(nodeId, packedData, sizeof(uint16_t));
|
||||
return sizeof(uint16_t);
|
||||
}
|
||||
|
||||
int packNodeId(unsigned char* packStore, uint16_t nodeId) {
|
||||
memcpy(packStore, &nodeId, sizeof(uint16_t));
|
||||
return sizeof(uint16_t);
|
||||
}
|
||||
|
||||
Node::Node(sockaddr* publicSocket, sockaddr* localSocket, char type, uint16_t nodeID) :
|
||||
_type(type),
|
||||
_nodeID(nodeID),
|
||||
_wakeMicrostamp(usecTimestampNow()),
|
||||
_lastHeardMicrostamp(usecTimestampNow()),
|
||||
_activeSocket(NULL),
|
||||
_bytesReceivedMovingAverage(NULL),
|
||||
_linkedData(NULL),
|
||||
_isAlive(true)
|
||||
{
|
||||
if (publicSocket) {
|
||||
_publicSocket = new sockaddr(*publicSocket);
|
||||
} else {
|
||||
_publicSocket = NULL;
|
||||
}
|
||||
|
||||
if (localSocket) {
|
||||
_localSocket = new sockaddr(*localSocket);
|
||||
} else {
|
||||
_localSocket = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
Node::~Node() {
|
||||
delete _publicSocket;
|
||||
delete _localSocket;
|
||||
delete _linkedData;
|
||||
delete _bytesReceivedMovingAverage;
|
||||
}
|
||||
|
||||
// Names of Node Types
|
||||
const char* NODE_TYPE_NAME_DOMAIN = "Domain";
|
||||
const char* NODE_TYPE_NAME_VOXEL_SERVER = "Voxel Server";
|
||||
const char* NODE_TYPE_NAME_INTERFACE = "Client Interface";
|
||||
const char* NODE_TYPE_NAME_AUDIO_MIXER = "Audio Mixer";
|
||||
const char* NODE_TYPE_NAME_AVATAR_MIXER = "Avatar Mixer";
|
||||
const char* NODE_TYPE_NAME_AUDIO_INJECTOR = "Audio Injector";
|
||||
const char* NODE_TYPE_NAME_ANIMATION_SERVER = "Animation Server";
|
||||
const char* NODE_TYPE_NAME_UNKNOWN = "Unknown";
|
||||
|
||||
const char* Node::getTypeName() const {
|
||||
switch (this->_type) {
|
||||
case NODE_TYPE_DOMAIN:
|
||||
return NODE_TYPE_NAME_DOMAIN;
|
||||
case NODE_TYPE_VOXEL_SERVER:
|
||||
return NODE_TYPE_NAME_VOXEL_SERVER;
|
||||
case NODE_TYPE_AGENT:
|
||||
return NODE_TYPE_NAME_INTERFACE;
|
||||
case NODE_TYPE_AUDIO_MIXER:
|
||||
return NODE_TYPE_NAME_AUDIO_MIXER;
|
||||
case NODE_TYPE_AVATAR_MIXER:
|
||||
return NODE_TYPE_NAME_AVATAR_MIXER;
|
||||
case NODE_TYPE_AUDIO_INJECTOR:
|
||||
return NODE_TYPE_NAME_AUDIO_INJECTOR;
|
||||
case NODE_TYPE_ANIMATION_SERVER:
|
||||
return NODE_TYPE_NAME_ANIMATION_SERVER;
|
||||
default:
|
||||
return NODE_TYPE_NAME_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
void Node::activateLocalSocket() {
|
||||
_activeSocket = _localSocket;
|
||||
}
|
||||
|
||||
void Node::activatePublicSocket() {
|
||||
_activeSocket = _publicSocket;
|
||||
}
|
||||
|
||||
bool Node::operator==(const Node& otherNode) {
|
||||
return matches(otherNode._publicSocket, otherNode._localSocket, otherNode._type);
|
||||
}
|
||||
|
||||
bool Node::matches(sockaddr* otherPublicSocket, sockaddr* otherLocalSocket, char otherNodeType) {
|
||||
// checks if two node objects are the same node (same type + local + public address)
|
||||
return _type == otherNodeType
|
||||
&& socketMatch(_publicSocket, otherPublicSocket)
|
||||
&& socketMatch(_localSocket, otherLocalSocket);
|
||||
}
|
||||
|
||||
void Node::recordBytesReceived(int bytesReceived) {
|
||||
if (_bytesReceivedMovingAverage == NULL) {
|
||||
_bytesReceivedMovingAverage = new SimpleMovingAverage(100);
|
||||
}
|
||||
|
||||
_bytesReceivedMovingAverage->updateAverage((float) bytesReceived);
|
||||
}
|
||||
|
||||
float Node::getAveragePacketsPerSecond() {
|
||||
if (_bytesReceivedMovingAverage) {
|
||||
return (1 / _bytesReceivedMovingAverage->getEventDeltaAverage());
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
float Node::getAverageKilobitsPerSecond() {
|
||||
if (_bytesReceivedMovingAverage) {
|
||||
return (_bytesReceivedMovingAverage->getAverageSampleValuePerSecond() * (8.0f / 1000));
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void Node::printLog(Node const& node) {
|
||||
|
||||
char publicAddressBuffer[16] = {'\0'};
|
||||
unsigned short publicAddressPort = loadBufferWithSocketInfo(publicAddressBuffer, node._publicSocket);
|
||||
|
||||
//char localAddressBuffer[16] = {'\0'};
|
||||
//unsigned short localAddressPort = loadBufferWithSocketInfo(localAddressBuffer, node.localSocket);
|
||||
|
||||
::printLog("# %d %s (%c) @ %s:%d\n",
|
||||
node._nodeID,
|
||||
node.getTypeName(),
|
||||
node._type,
|
||||
publicAddressBuffer,
|
||||
publicAddressPort);
|
||||
}
|
|
@ -1,13 +1,13 @@
|
|||
//
|
||||
// Agent.h
|
||||
// Node.h
|
||||
// hifi
|
||||
//
|
||||
// Created by Stephen Birarda on 2/15/13.
|
||||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef __hifi__Agent__
|
||||
#define __hifi__Agent__
|
||||
#ifndef __hifi__Node__
|
||||
#define __hifi__Node__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <ostream>
|
||||
|
@ -19,23 +19,23 @@
|
|||
#endif
|
||||
|
||||
#include "SimpleMovingAverage.h"
|
||||
#include "AgentData.h"
|
||||
#include "NodeData.h"
|
||||
|
||||
class Agent {
|
||||
class Node {
|
||||
public:
|
||||
Agent(sockaddr* publicSocket, sockaddr* localSocket, char type, uint16_t agentID);
|
||||
~Agent();
|
||||
Node(sockaddr* publicSocket, sockaddr* localSocket, char type, uint16_t nodeID);
|
||||
~Node();
|
||||
|
||||
bool operator==(const Agent& otherAgent);
|
||||
bool operator==(const Node& otherNode);
|
||||
|
||||
bool matches(sockaddr* otherPublicSocket, sockaddr* otherLocalSocket, char otherAgentType);
|
||||
bool matches(sockaddr* otherPublicSocket, sockaddr* otherLocalSocket, char otherNodeType);
|
||||
|
||||
char getType() const { return _type; }
|
||||
void setType(char type) { _type = type; }
|
||||
const char* getTypeName() const;
|
||||
|
||||
uint16_t getAgentID() const { return _agentID; }
|
||||
void setAgentID(uint16_t agentID) { _agentID = agentID;}
|
||||
uint16_t getNodeID() const { return _nodeID; }
|
||||
void setNodeID(uint16_t nodeID) { _nodeID = nodeID;}
|
||||
|
||||
long long getWakeMicrostamp() const { return _wakeMicrostamp; }
|
||||
void setWakeMicrostamp(long long wakeMicrostamp) { _wakeMicrostamp = wakeMicrostamp; }
|
||||
|
@ -53,8 +53,8 @@ public:
|
|||
void activatePublicSocket();
|
||||
void activateLocalSocket();
|
||||
|
||||
AgentData* getLinkedData() const { return _linkedData; }
|
||||
void setLinkedData(AgentData* linkedData) { _linkedData = linkedData; }
|
||||
NodeData* getLinkedData() const { return _linkedData; }
|
||||
void setLinkedData(NodeData* linkedData) { _linkedData = linkedData; }
|
||||
|
||||
bool isAlive() const { return _isAlive; };
|
||||
void setAlive(bool isAlive) { _isAlive = isAlive; };
|
||||
|
@ -66,27 +66,27 @@ public:
|
|||
int getPingMs() const { return _pingMs; };
|
||||
void setPingMs(int pingMs) { _pingMs = pingMs; };
|
||||
|
||||
static void printLog(Agent const&);
|
||||
static void printLog(Node const&);
|
||||
private:
|
||||
// privatize copy and assignment operator to disallow Agent copying
|
||||
Agent(const Agent &otherAgent);
|
||||
Agent& operator=(Agent otherAgent);
|
||||
// privatize copy and assignment operator to disallow Node copying
|
||||
Node(const Node &otherNode);
|
||||
Node& operator=(Node otherNode);
|
||||
|
||||
char _type;
|
||||
uint16_t _agentID;
|
||||
uint16_t _nodeID;
|
||||
long long _wakeMicrostamp;
|
||||
long long _lastHeardMicrostamp;
|
||||
sockaddr* _publicSocket;
|
||||
sockaddr* _localSocket;
|
||||
sockaddr* _activeSocket;
|
||||
SimpleMovingAverage* _bytesReceivedMovingAverage;
|
||||
AgentData* _linkedData;
|
||||
NodeData* _linkedData;
|
||||
bool _isAlive;
|
||||
int _pingMs;
|
||||
};
|
||||
|
||||
|
||||
int unpackAgentId(unsigned char *packedData, uint16_t *agentId);
|
||||
int packAgentId(unsigned char *packStore, uint16_t agentId);
|
||||
int unpackNodeId(unsigned char *packedData, uint16_t *nodeId);
|
||||
int packNodeId(unsigned char *packStore, uint16_t nodeId);
|
||||
|
||||
#endif /* defined(__hifi__Agent__) */
|
||||
#endif /* defined(__hifi__Node__) */
|
17
libraries/shared/src/NodeData.cpp
Normal file
17
libraries/shared/src/NodeData.cpp
Normal file
|
@ -0,0 +1,17 @@
|
|||
//
|
||||
// NodeData.cpp
|
||||
// hifi
|
||||
//
|
||||
// Created by Stephen Birarda on 2/19/13.
|
||||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#include "NodeData.h"
|
||||
|
||||
NodeData::NodeData(Node* owningNode) :
|
||||
_owningNode(owningNode)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
NodeData::~NodeData() {}
|
|
@ -1,26 +1,26 @@
|
|||
//
|
||||
// AgentData.h
|
||||
// NodeData.h
|
||||
// hifi
|
||||
//
|
||||
// Created by Stephen Birarda on 2/19/13.
|
||||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef hifi_AgentData_h
|
||||
#define hifi_AgentData_h
|
||||
#ifndef hifi_NodeData_h
|
||||
#define hifi_NodeData_h
|
||||
|
||||
class Agent;
|
||||
class Node;
|
||||
|
||||
class AgentData {
|
||||
class NodeData {
|
||||
public:
|
||||
AgentData(Agent* owningAgent);
|
||||
NodeData(Node* owningNode);
|
||||
|
||||
virtual ~AgentData() = 0;
|
||||
virtual ~NodeData() = 0;
|
||||
virtual int parseData(unsigned char* sourceBuffer, int numBytes) = 0;
|
||||
|
||||
Agent* getOwningAgent() { return _owningAgent; }
|
||||
Node* getOwningNode() { return _owningNode; }
|
||||
protected:
|
||||
Agent* _owningAgent;
|
||||
Node* _owningNode;
|
||||
};
|
||||
|
||||
#endif
|
556
libraries/shared/src/NodeList.cpp
Normal file
556
libraries/shared/src/NodeList.cpp
Normal file
|
@ -0,0 +1,556 @@
|
|||
//
|
||||
// NodeList.cpp
|
||||
// hifi
|
||||
//
|
||||
// Created by Stephen Birarda on 2/15/13.
|
||||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#include <pthread.h>
|
||||
#include <cstring>
|
||||
#include <cstdlib>
|
||||
#include <cstdio>
|
||||
|
||||
#include "NodeList.h"
|
||||
#include "NodeTypes.h"
|
||||
#include "PacketHeaders.h"
|
||||
#include "SharedUtil.h"
|
||||
#include "Log.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "Syssocket.h"
|
||||
#else
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
const char SOLO_NODE_TYPES[3] = {
|
||||
NODE_TYPE_AVATAR_MIXER,
|
||||
NODE_TYPE_AUDIO_MIXER,
|
||||
NODE_TYPE_VOXEL_SERVER
|
||||
};
|
||||
|
||||
char DOMAIN_HOSTNAME[] = "highfidelity.below92.com";
|
||||
char DOMAIN_IP[100] = ""; // IP Address will be re-set by lookup on startup
|
||||
const int DOMAINSERVER_PORT = 40102;
|
||||
|
||||
bool silentNodeThreadStopFlag = false;
|
||||
bool pingUnknownNodeThreadStopFlag = false;
|
||||
|
||||
NodeList* NodeList::_sharedInstance = NULL;
|
||||
|
||||
NodeList* NodeList::createInstance(char ownerType, unsigned int socketListenPort) {
|
||||
if (!_sharedInstance) {
|
||||
_sharedInstance = new NodeList(ownerType, socketListenPort);
|
||||
} else {
|
||||
printLog("NodeList createInstance called with existing instance.\n");
|
||||
}
|
||||
|
||||
return _sharedInstance;
|
||||
}
|
||||
|
||||
NodeList* NodeList::getInstance() {
|
||||
if (!_sharedInstance) {
|
||||
printLog("NodeList getInstance called before call to createInstance. Returning NULL pointer.\n");
|
||||
}
|
||||
|
||||
return _sharedInstance;
|
||||
}
|
||||
|
||||
NodeList::NodeList(char newOwnerType, unsigned int newSocketListenPort) :
|
||||
_nodeBuckets(),
|
||||
_numNodes(0),
|
||||
_nodeSocket(newSocketListenPort),
|
||||
_ownerType(newOwnerType),
|
||||
_nodeTypesOfInterest(NULL),
|
||||
_ownerID(UNKNOWN_NODE_ID),
|
||||
_lastNodeID(0) {
|
||||
pthread_mutex_init(&mutex, 0);
|
||||
}
|
||||
|
||||
NodeList::~NodeList() {
|
||||
delete _nodeTypesOfInterest;
|
||||
|
||||
// stop the spawned threads, if they were started
|
||||
stopSilentNodeRemovalThread();
|
||||
stopPingUnknownNodesThread();
|
||||
|
||||
pthread_mutex_destroy(&mutex);
|
||||
}
|
||||
|
||||
void NodeList::timePingReply(sockaddr *nodeAddress, unsigned char *packetData) {
|
||||
for(NodeList::iterator node = begin(); node != end(); node++) {
|
||||
if (socketMatch(node->getPublicSocket(), nodeAddress) ||
|
||||
socketMatch(node->getLocalSocket(), nodeAddress)) {
|
||||
int pingTime = usecTimestampNow() - *(long long *)(packetData + 1);
|
||||
node->setPingMs(pingTime / 1000);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NodeList::processNodeData(sockaddr *senderAddress, unsigned char *packetData, size_t dataBytes) {
|
||||
switch (((char *)packetData)[0]) {
|
||||
case PACKET_HEADER_DOMAIN: {
|
||||
processDomainServerList(packetData, dataBytes);
|
||||
break;
|
||||
}
|
||||
case PACKET_HEADER_PING: {
|
||||
char pingPacket[dataBytes];
|
||||
memcpy(pingPacket, packetData, dataBytes);
|
||||
pingPacket[0] = PACKET_HEADER_PING_REPLY;
|
||||
_nodeSocket.send(senderAddress, pingPacket, dataBytes);
|
||||
break;
|
||||
}
|
||||
case PACKET_HEADER_PING_REPLY: {
|
||||
timePingReply(senderAddress, packetData);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NodeList::processBulkNodeData(sockaddr *senderAddress, unsigned char *packetData, int numTotalBytes) {
|
||||
lock();
|
||||
|
||||
// find the avatar mixer in our node list and update the lastRecvTime from it
|
||||
Node* bulkSendNode = nodeWithAddress(senderAddress);
|
||||
|
||||
if (bulkSendNode) {
|
||||
bulkSendNode->setLastHeardMicrostamp(usecTimestampNow());
|
||||
bulkSendNode->recordBytesReceived(numTotalBytes);
|
||||
}
|
||||
|
||||
unsigned char *startPosition = packetData;
|
||||
unsigned char *currentPosition = startPosition + 1;
|
||||
unsigned char packetHolder[numTotalBytes];
|
||||
|
||||
packetHolder[0] = PACKET_HEADER_HEAD_DATA;
|
||||
|
||||
uint16_t nodeID = -1;
|
||||
|
||||
while ((currentPosition - startPosition) < numTotalBytes) {
|
||||
unpackNodeId(currentPosition, &nodeID);
|
||||
memcpy(packetHolder + 1, currentPosition, numTotalBytes - (currentPosition - startPosition));
|
||||
|
||||
Node* matchingNode = nodeWithID(nodeID);
|
||||
|
||||
if (!matchingNode) {
|
||||
// we're missing this node, we need to add it to the list
|
||||
matchingNode = addOrUpdateNode(NULL, NULL, NODE_TYPE_AGENT, nodeID);
|
||||
}
|
||||
|
||||
currentPosition += updateNodeWithData(matchingNode,
|
||||
packetHolder,
|
||||
numTotalBytes - (currentPosition - startPosition));
|
||||
}
|
||||
|
||||
unlock();
|
||||
}
|
||||
|
||||
int NodeList::updateNodeWithData(sockaddr *senderAddress, unsigned char *packetData, size_t dataBytes) {
|
||||
// find the node by the sockaddr
|
||||
Node* matchingNode = nodeWithAddress(senderAddress);
|
||||
|
||||
if (matchingNode) {
|
||||
return updateNodeWithData(matchingNode, packetData, dataBytes);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int NodeList::updateNodeWithData(Node *node, unsigned char *packetData, int dataBytes) {
|
||||
node->setLastHeardMicrostamp(usecTimestampNow());
|
||||
|
||||
if (node->getActiveSocket()) {
|
||||
node->recordBytesReceived(dataBytes);
|
||||
}
|
||||
|
||||
if (!node->getLinkedData() && linkedDataCreateCallback) {
|
||||
linkedDataCreateCallback(node);
|
||||
}
|
||||
|
||||
return node->getLinkedData()->parseData(packetData, dataBytes);
|
||||
}
|
||||
|
||||
Node* NodeList::nodeWithAddress(sockaddr *senderAddress) {
|
||||
for(NodeList::iterator node = begin(); node != end(); node++) {
|
||||
if (node->getActiveSocket() && socketMatch(node->getActiveSocket(), senderAddress)) {
|
||||
return &(*node);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Node* NodeList::nodeWithID(uint16_t nodeID) {
|
||||
for(NodeList::iterator node = begin(); node != end(); node++) {
|
||||
if (node->getNodeID() == nodeID) {
|
||||
return &(*node);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int NodeList::getNumAliveNodes() const {
|
||||
int numAliveNodes = 0;
|
||||
|
||||
for (NodeList::iterator node = begin(); node != end(); node++) {
|
||||
if (node->isAlive()) {
|
||||
++numAliveNodes;
|
||||
}
|
||||
}
|
||||
|
||||
return numAliveNodes;
|
||||
}
|
||||
|
||||
void NodeList::setNodeTypesOfInterest(const char* nodeTypesOfInterest, int numNodeTypesOfInterest) {
|
||||
delete _nodeTypesOfInterest;
|
||||
|
||||
_nodeTypesOfInterest = new char[numNodeTypesOfInterest + sizeof(char)];
|
||||
memcpy(_nodeTypesOfInterest, nodeTypesOfInterest, numNodeTypesOfInterest);
|
||||
_nodeTypesOfInterest[numNodeTypesOfInterest] = '\0';
|
||||
}
|
||||
|
||||
void NodeList::sendDomainServerCheckIn() {
|
||||
static bool printedDomainServerIP = false;
|
||||
// Lookup the IP address of the domain server if we need to
|
||||
if (atoi(DOMAIN_IP) == 0) {
|
||||
struct hostent* pHostInfo;
|
||||
if ((pHostInfo = gethostbyname(DOMAIN_HOSTNAME)) != NULL) {
|
||||
sockaddr_in tempAddress;
|
||||
memcpy(&tempAddress.sin_addr, pHostInfo->h_addr_list[0], pHostInfo->h_length);
|
||||
strcpy(DOMAIN_IP, inet_ntoa(tempAddress.sin_addr));
|
||||
printLog("Domain Server: %s \n", DOMAIN_HOSTNAME);
|
||||
} else {
|
||||
printLog("Failed domain server lookup\n");
|
||||
}
|
||||
} else if (!printedDomainServerIP) {
|
||||
printLog("Domain Server IP: %s\n", DOMAIN_IP);
|
||||
printedDomainServerIP = true;
|
||||
}
|
||||
|
||||
// construct the DS check in packet if we need to
|
||||
static unsigned char* checkInPacket = NULL;
|
||||
static int checkInPacketSize;
|
||||
|
||||
if (!checkInPacket) {
|
||||
int numBytesNodesOfInterest = _nodeTypesOfInterest ? strlen((char*) _nodeTypesOfInterest) : 0;
|
||||
|
||||
// check in packet has header, node type, port, IP, node types of interest, null termination
|
||||
int numPacketBytes = sizeof(PACKET_HEADER) + sizeof(NODE_TYPE) + sizeof(uint16_t) + (sizeof(char) * 4) +
|
||||
numBytesNodesOfInterest + sizeof(unsigned char);
|
||||
|
||||
checkInPacket = new unsigned char[numPacketBytes];
|
||||
unsigned char* packetPosition = checkInPacket;
|
||||
|
||||
*(packetPosition++) = (memchr(SOLO_NODE_TYPES, _ownerType, sizeof(SOLO_NODE_TYPES)))
|
||||
? PACKET_HEADER_DOMAIN_REPORT_FOR_DUTY
|
||||
: PACKET_HEADER_DOMAIN_LIST_REQUEST;
|
||||
*(packetPosition++) = _ownerType;
|
||||
|
||||
packetPosition += packSocket(checkInPacket + sizeof(PACKET_HEADER) + sizeof(NODE_TYPE),
|
||||
getLocalAddress(),
|
||||
htons(_nodeSocket.getListeningPort()));
|
||||
|
||||
// add the number of bytes for node types of interest
|
||||
*(packetPosition++) = numBytesNodesOfInterest;
|
||||
|
||||
// copy over the bytes for node types of interest, if required
|
||||
if (numBytesNodesOfInterest > 0) {
|
||||
memcpy(packetPosition,
|
||||
_nodeTypesOfInterest,
|
||||
numBytesNodesOfInterest);
|
||||
packetPosition += numBytesNodesOfInterest;
|
||||
}
|
||||
|
||||
checkInPacketSize = packetPosition - checkInPacket;
|
||||
}
|
||||
|
||||
_nodeSocket.send(DOMAIN_IP, DOMAINSERVER_PORT, checkInPacket, checkInPacketSize);
|
||||
}
|
||||
|
||||
int NodeList::processDomainServerList(unsigned char *packetData, size_t dataBytes) {
|
||||
int readNodes = 0;
|
||||
|
||||
char nodeType;
|
||||
uint16_t nodeId;
|
||||
|
||||
// assumes only IPv4 addresses
|
||||
sockaddr_in nodePublicSocket;
|
||||
nodePublicSocket.sin_family = AF_INET;
|
||||
sockaddr_in nodeLocalSocket;
|
||||
nodeLocalSocket.sin_family = AF_INET;
|
||||
|
||||
unsigned char *readPtr = packetData + 1;
|
||||
unsigned char *startPtr = packetData;
|
||||
|
||||
while((readPtr - startPtr) < dataBytes - sizeof(uint16_t)) {
|
||||
nodeType = *readPtr++;
|
||||
readPtr += unpackNodeId(readPtr, (uint16_t *)&nodeId);
|
||||
readPtr += unpackSocket(readPtr, (sockaddr *)&nodePublicSocket);
|
||||
readPtr += unpackSocket(readPtr, (sockaddr *)&nodeLocalSocket);
|
||||
|
||||
addOrUpdateNode((sockaddr *)&nodePublicSocket, (sockaddr *)&nodeLocalSocket, nodeType, nodeId);
|
||||
}
|
||||
|
||||
// read out our ID from the packet
|
||||
unpackNodeId(readPtr, &_ownerID);
|
||||
|
||||
return readNodes;
|
||||
}
|
||||
|
||||
Node* NodeList::addOrUpdateNode(sockaddr* publicSocket, sockaddr* localSocket, char nodeType, uint16_t nodeId) {
|
||||
NodeList::iterator node = end();
|
||||
|
||||
if (publicSocket) {
|
||||
for (node = begin(); node != end(); node++) {
|
||||
if (node->matches(publicSocket, localSocket, nodeType)) {
|
||||
// we already have this node, stop checking
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (node == end()) {
|
||||
// we didn't have this node, so add them
|
||||
Node* newNode = new Node(publicSocket, localSocket, nodeType, nodeId);
|
||||
|
||||
if (socketMatch(publicSocket, localSocket)) {
|
||||
// likely debugging scenario with two nodes on local network
|
||||
// set the node active right away
|
||||
newNode->activatePublicSocket();
|
||||
}
|
||||
|
||||
if (newNode->getType() == NODE_TYPE_VOXEL_SERVER ||
|
||||
newNode->getType() == NODE_TYPE_AVATAR_MIXER ||
|
||||
newNode->getType() == NODE_TYPE_AUDIO_MIXER) {
|
||||
// this is currently the cheat we use to talk directly to our test servers on EC2
|
||||
// to be removed when we have a proper identification strategy
|
||||
newNode->activatePublicSocket();
|
||||
}
|
||||
|
||||
addNodeToList(newNode);
|
||||
|
||||
return newNode;
|
||||
} else {
|
||||
|
||||
if (node->getType() == NODE_TYPE_AUDIO_MIXER ||
|
||||
node->getType() == NODE_TYPE_VOXEL_SERVER) {
|
||||
// until the Audio class also uses our nodeList, we need to update
|
||||
// the lastRecvTimeUsecs for the audio mixer so it doesn't get killed and re-added continously
|
||||
node->setLastHeardMicrostamp(usecTimestampNow());
|
||||
}
|
||||
|
||||
// we had this node already, do nothing for now
|
||||
return &*node;
|
||||
}
|
||||
}
|
||||
|
||||
void NodeList::addNodeToList(Node* newNode) {
|
||||
// find the correct array to add this node to
|
||||
int bucketIndex = _numNodes / NODES_PER_BUCKET;
|
||||
|
||||
if (!_nodeBuckets[bucketIndex]) {
|
||||
_nodeBuckets[bucketIndex] = new Node*[NODES_PER_BUCKET]();
|
||||
}
|
||||
|
||||
_nodeBuckets[bucketIndex][_numNodes % NODES_PER_BUCKET] = newNode;
|
||||
|
||||
++_numNodes;
|
||||
|
||||
printLog("Added ");
|
||||
Node::printLog(*newNode);
|
||||
}
|
||||
|
||||
unsigned NodeList::broadcastToNodes(unsigned char *broadcastData, size_t dataBytes, const char* nodeTypes, int numNodeTypes) {
|
||||
unsigned n = 0;
|
||||
for(NodeList::iterator node = begin(); node != end(); node++) {
|
||||
// only send to the NodeTypes we are asked to send to.
|
||||
if (node->getActiveSocket() != NULL && memchr(nodeTypes, node->getType(), numNodeTypes)) {
|
||||
// we know which socket is good for this node, send there
|
||||
_nodeSocket.send(node->getActiveSocket(), broadcastData, dataBytes);
|
||||
++n;
|
||||
}
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
void NodeList::handlePingReply(sockaddr *nodeAddress) {
|
||||
for(NodeList::iterator node = begin(); node != end(); node++) {
|
||||
// check both the public and local addresses for each node to see if we find a match
|
||||
// prioritize the private address so that we prune erroneous local matches
|
||||
if (socketMatch(node->getPublicSocket(), nodeAddress)) {
|
||||
node->activatePublicSocket();
|
||||
break;
|
||||
} else if (socketMatch(node->getLocalSocket(), nodeAddress)) {
|
||||
node->activateLocalSocket();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Node* NodeList::soloNodeOfType(char nodeType) {
|
||||
if (memchr(SOLO_NODE_TYPES, nodeType, sizeof(SOLO_NODE_TYPES)) != NULL) {
|
||||
for(NodeList::iterator node = begin(); node != end(); node++) {
|
||||
if (node->getType() == nodeType) {
|
||||
return &(*node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *pingUnknownNodes(void *args) {
|
||||
|
||||
NodeList* nodeList = (NodeList*) args;
|
||||
const int PING_INTERVAL_USECS = 1 * 1000000;
|
||||
|
||||
timeval lastSend;
|
||||
|
||||
while (!pingUnknownNodeThreadStopFlag) {
|
||||
gettimeofday(&lastSend, NULL);
|
||||
|
||||
for(NodeList::iterator node = nodeList->begin();
|
||||
node != nodeList->end();
|
||||
node++) {
|
||||
if (!node->getActiveSocket() && node->getPublicSocket() && node->getLocalSocket()) {
|
||||
// ping both of the sockets for the node so we can figure out
|
||||
// which socket we can use
|
||||
nodeList->getNodeSocket()->send(node->getPublicSocket(), &PACKET_HEADER_PING, 1);
|
||||
nodeList->getNodeSocket()->send(node->getLocalSocket(), &PACKET_HEADER_PING, 1);
|
||||
}
|
||||
}
|
||||
|
||||
long long usecToSleep = PING_INTERVAL_USECS - (usecTimestampNow() - usecTimestamp(&lastSend));
|
||||
|
||||
if (usecToSleep > 0) {
|
||||
usleep(usecToSleep);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void NodeList::startPingUnknownNodesThread() {
|
||||
pthread_create(&pingUnknownNodesThread, NULL, pingUnknownNodes, (void *)this);
|
||||
}
|
||||
|
||||
void NodeList::stopPingUnknownNodesThread() {
|
||||
pingUnknownNodeThreadStopFlag = true;
|
||||
pthread_join(pingUnknownNodesThread, NULL);
|
||||
}
|
||||
|
||||
void *removeSilentNodes(void *args) {
|
||||
NodeList* nodeList = (NodeList*) args;
|
||||
long long checkTimeUSecs, sleepTime;
|
||||
|
||||
while (!silentNodeThreadStopFlag) {
|
||||
checkTimeUSecs = usecTimestampNow();
|
||||
|
||||
for(NodeList::iterator node = nodeList->begin(); node != nodeList->end(); ++node) {
|
||||
|
||||
if ((checkTimeUSecs - node->getLastHeardMicrostamp()) > NODE_SILENCE_THRESHOLD_USECS
|
||||
&& node->getType() != NODE_TYPE_VOXEL_SERVER) {
|
||||
|
||||
printLog("Killed ");
|
||||
Node::printLog(*node);
|
||||
|
||||
node->setAlive(false);
|
||||
}
|
||||
}
|
||||
|
||||
sleepTime = NODE_SILENCE_THRESHOLD_USECS - (usecTimestampNow() - checkTimeUSecs);
|
||||
#ifdef _WIN32
|
||||
Sleep( static_cast<int>(1000.0f*sleepTime) );
|
||||
#else
|
||||
usleep(sleepTime);
|
||||
#endif
|
||||
}
|
||||
|
||||
pthread_exit(0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void NodeList::startSilentNodeRemovalThread() {
|
||||
pthread_create(&removeSilentNodesThread, NULL, removeSilentNodes, (void*) this);
|
||||
}
|
||||
|
||||
void NodeList::stopSilentNodeRemovalThread() {
|
||||
silentNodeThreadStopFlag = true;
|
||||
pthread_join(removeSilentNodesThread, NULL);
|
||||
}
|
||||
|
||||
NodeList::iterator NodeList::begin() const {
|
||||
Node** nodeBucket = NULL;
|
||||
|
||||
for (int i = 0; i < _numNodes; i++) {
|
||||
if (i % NODES_PER_BUCKET == 0) {
|
||||
nodeBucket = _nodeBuckets[i / NODES_PER_BUCKET];
|
||||
}
|
||||
|
||||
if (nodeBucket[i % NODES_PER_BUCKET]->isAlive()) {
|
||||
return NodeListIterator(this, i);
|
||||
}
|
||||
}
|
||||
|
||||
// there's no alive node to start from - return the end
|
||||
return end();
|
||||
}
|
||||
|
||||
NodeList::iterator NodeList::end() const {
|
||||
return NodeListIterator(this, _numNodes);
|
||||
}
|
||||
|
||||
NodeListIterator::NodeListIterator(const NodeList* nodeList, int nodeIndex) :
|
||||
_nodeIndex(nodeIndex) {
|
||||
_nodeList = nodeList;
|
||||
}
|
||||
|
||||
NodeListIterator& NodeListIterator::operator=(const NodeListIterator& otherValue) {
|
||||
_nodeList = otherValue._nodeList;
|
||||
_nodeIndex = otherValue._nodeIndex;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool NodeListIterator::operator==(const NodeListIterator &otherValue) {
|
||||
return _nodeIndex == otherValue._nodeIndex;
|
||||
}
|
||||
|
||||
bool NodeListIterator::operator!=(const NodeListIterator &otherValue) {
|
||||
return !(*this == otherValue);
|
||||
}
|
||||
|
||||
Node& NodeListIterator::operator*() {
|
||||
Node** nodeBucket = _nodeList->_nodeBuckets[_nodeIndex / NODES_PER_BUCKET];
|
||||
return *nodeBucket[_nodeIndex % NODES_PER_BUCKET];
|
||||
}
|
||||
|
||||
Node* NodeListIterator::operator->() {
|
||||
Node** nodeBucket = _nodeList->_nodeBuckets[_nodeIndex / NODES_PER_BUCKET];
|
||||
return nodeBucket[_nodeIndex % NODES_PER_BUCKET];
|
||||
}
|
||||
|
||||
NodeListIterator& NodeListIterator::operator++() {
|
||||
skipDeadAndStopIncrement();
|
||||
return *this;
|
||||
}
|
||||
|
||||
NodeList::iterator NodeListIterator::operator++(int) {
|
||||
NodeListIterator newIterator = NodeListIterator(*this);
|
||||
skipDeadAndStopIncrement();
|
||||
return newIterator;
|
||||
}
|
||||
|
||||
void NodeListIterator::skipDeadAndStopIncrement() {
|
||||
while (_nodeIndex != _nodeList->_numNodes) {
|
||||
++_nodeIndex;
|
||||
|
||||
if (_nodeIndex == _nodeList->_numNodes) {
|
||||
break;
|
||||
} else if ((*(*this)).isAlive()) {
|
||||
// skip over the dead nodes
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
147
libraries/shared/src/NodeList.h
Normal file
147
libraries/shared/src/NodeList.h
Normal file
|
@ -0,0 +1,147 @@
|
|||
//
|
||||
// NodeList.h
|
||||
// hifi
|
||||
//
|
||||
// Created by Stephen Birarda on 2/15/13.
|
||||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef __hifi__NodeList__
|
||||
#define __hifi__NodeList__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <iterator>
|
||||
|
||||
#include "Node.h"
|
||||
#include "UDPSocket.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "pthread.h"
|
||||
#endif
|
||||
|
||||
const int MAX_NUM_NODES = 10000;
|
||||
const int NODES_PER_BUCKET = 100;
|
||||
|
||||
const int MAX_PACKET_SIZE = 1500;
|
||||
const unsigned int NODE_SOCKET_LISTEN_PORT = 40103;
|
||||
|
||||
const int NODE_SILENCE_THRESHOLD_USECS = 2 * 1000000;
|
||||
const int DOMAIN_SERVER_CHECK_IN_USECS = 1 * 1000000;
|
||||
|
||||
extern const char SOLO_NODE_TYPES[3];
|
||||
|
||||
extern char DOMAIN_HOSTNAME[];
|
||||
extern char DOMAIN_IP[100]; // IP Address will be re-set by lookup on startup
|
||||
extern const int DOMAINSERVER_PORT;
|
||||
|
||||
const int UNKNOWN_NODE_ID = -1;
|
||||
|
||||
class NodeListIterator;
|
||||
|
||||
class NodeList {
|
||||
public:
|
||||
static NodeList* createInstance(char ownerType, unsigned int socketListenPort = NODE_SOCKET_LISTEN_PORT);
|
||||
static NodeList* getInstance();
|
||||
|
||||
typedef NodeListIterator iterator;
|
||||
|
||||
NodeListIterator begin() const;
|
||||
NodeListIterator end() const;
|
||||
|
||||
char getOwnerType() const { return _ownerType; }
|
||||
|
||||
uint16_t getLastNodeID() const { return _lastNodeID; }
|
||||
void increaseNodeID() { ++_lastNodeID; }
|
||||
|
||||
uint16_t getOwnerID() const { return _ownerID; }
|
||||
void setOwnerID(uint16_t ownerID) { _ownerID = ownerID; }
|
||||
|
||||
UDPSocket* getNodeSocket() { return &_nodeSocket; }
|
||||
|
||||
unsigned int getSocketListenPort() const { return _nodeSocket.getListeningPort(); };
|
||||
|
||||
void(*linkedDataCreateCallback)(Node *);
|
||||
|
||||
int size() { return _numNodes; }
|
||||
int getNumAliveNodes() const;
|
||||
|
||||
void lock() { pthread_mutex_lock(&mutex); }
|
||||
void unlock() { pthread_mutex_unlock(&mutex); }
|
||||
|
||||
void setNodeTypesOfInterest(const char* nodeTypesOfInterest, int numNodeTypesOfInterest);
|
||||
void sendDomainServerCheckIn();
|
||||
int processDomainServerList(unsigned char *packetData, size_t dataBytes);
|
||||
|
||||
Node* nodeWithAddress(sockaddr *senderAddress);
|
||||
Node* nodeWithID(uint16_t nodeID);
|
||||
|
||||
Node* addOrUpdateNode(sockaddr* publicSocket, sockaddr* localSocket, char nodeType, uint16_t nodeId);
|
||||
|
||||
void processNodeData(sockaddr *senderAddress, unsigned char *packetData, size_t dataBytes);
|
||||
void processBulkNodeData(sockaddr *senderAddress, unsigned char *packetData, int numTotalBytes);
|
||||
|
||||
int updateNodeWithData(sockaddr *senderAddress, unsigned char *packetData, size_t dataBytes);
|
||||
int updateNodeWithData(Node *node, unsigned char *packetData, int dataBytes);
|
||||
|
||||
unsigned broadcastToNodes(unsigned char *broadcastData, size_t dataBytes, const char* nodeTypes, int numNodeTypes);
|
||||
|
||||
Node* soloNodeOfType(char nodeType);
|
||||
|
||||
void startSilentNodeRemovalThread();
|
||||
void stopSilentNodeRemovalThread();
|
||||
void startPingUnknownNodesThread();
|
||||
void stopPingUnknownNodesThread();
|
||||
|
||||
friend class NodeListIterator;
|
||||
private:
|
||||
static NodeList* _sharedInstance;
|
||||
|
||||
NodeList(char ownerType, unsigned int socketListenPort);
|
||||
~NodeList();
|
||||
NodeList(NodeList const&); // Don't implement, needed to avoid copies of singleton
|
||||
void operator=(NodeList const&); // Don't implement, needed to avoid copies of singleton
|
||||
|
||||
void addNodeToList(Node* newNode);
|
||||
|
||||
Node** _nodeBuckets[MAX_NUM_NODES / NODES_PER_BUCKET];
|
||||
int _numNodes;
|
||||
UDPSocket _nodeSocket;
|
||||
char _ownerType;
|
||||
char* _nodeTypesOfInterest;
|
||||
unsigned int _socketListenPort;
|
||||
uint16_t _ownerID;
|
||||
uint16_t _lastNodeID;
|
||||
pthread_t removeSilentNodesThread;
|
||||
pthread_t checkInWithDomainServerThread;
|
||||
pthread_t pingUnknownNodesThread;
|
||||
pthread_mutex_t mutex;
|
||||
|
||||
void handlePingReply(sockaddr *nodeAddress);
|
||||
void timePingReply(sockaddr *nodeAddress, unsigned char *packetData);
|
||||
};
|
||||
|
||||
class NodeListIterator : public std::iterator<std::input_iterator_tag, Node> {
|
||||
public:
|
||||
NodeListIterator(const NodeList* nodeList, int nodeIndex);
|
||||
~NodeListIterator() {};
|
||||
|
||||
int getNodeIndex() { return _nodeIndex; };
|
||||
|
||||
NodeListIterator& operator=(const NodeListIterator& otherValue);
|
||||
|
||||
bool operator==(const NodeListIterator& otherValue);
|
||||
bool operator!= (const NodeListIterator& otherValue);
|
||||
|
||||
Node& operator*();
|
||||
Node* operator->();
|
||||
|
||||
NodeListIterator& operator++();
|
||||
NodeListIterator operator++(int);
|
||||
private:
|
||||
void skipDeadAndStopIncrement();
|
||||
|
||||
const NodeList* _nodeList;
|
||||
int _nodeIndex;
|
||||
};
|
||||
|
||||
#endif /* defined(__hifi__NodeList__) */
|
28
libraries/shared/src/NodeTypes.h
Normal file
28
libraries/shared/src/NodeTypes.h
Normal file
|
@ -0,0 +1,28 @@
|
|||
//
|
||||
// NodeTypes.h
|
||||
// hifi
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 2013/04/09
|
||||
// Copyright (c) 2013 HighFidelity, Inc. All rights reserved.
|
||||
//
|
||||
// Single byte/character Node Types used to identify various nodes in the system.
|
||||
// For example, an node whose is 'V' is always a voxel server.
|
||||
|
||||
#ifndef hifi_NodeTypes_h
|
||||
#define hifi_NodeTypes_h
|
||||
|
||||
// NOTE: If you add a new NODE_TYPE_XXX then you also should add a new NODE_TYPE_NAME_XXX and a new "case" to the
|
||||
// switch statement in Node.cpp specifically Node::getTypeName().
|
||||
// If you don't then it will make things harder on your co-developers in debugging because the Node
|
||||
// class won't know the name and will report it as "Unknown".
|
||||
|
||||
typedef char NODE_TYPE;
|
||||
const NODE_TYPE NODE_TYPE_DOMAIN = 'D';
|
||||
const NODE_TYPE NODE_TYPE_VOXEL_SERVER = 'V';
|
||||
const NODE_TYPE NODE_TYPE_AGENT = 'I';
|
||||
const NODE_TYPE NODE_TYPE_AUDIO_MIXER = 'M';
|
||||
const NODE_TYPE NODE_TYPE_AVATAR_MIXER = 'W';
|
||||
const NODE_TYPE NODE_TYPE_AUDIO_INJECTOR = 'A';
|
||||
const NODE_TYPE NODE_TYPE_ANIMATION_SERVER = 'a';
|
||||
|
||||
#endif
|
|
@ -73,7 +73,7 @@ int unpackSocket(unsigned char* packedData, sockaddr* unpackDestSocket) {
|
|||
}
|
||||
|
||||
int getLocalAddress() {
|
||||
// get this agent's local address so we can pass that to DS
|
||||
// get this node's local address so we can pass that to DS
|
||||
struct ifaddrs* ifAddrStruct = NULL;
|
||||
struct ifaddrs* ifa = NULL;
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// VoxelAgentData.cpp
|
||||
// VoxelNodeData.cpp
|
||||
// hifi
|
||||
//
|
||||
// Created by Stephen Birarda on 3/21/13.
|
||||
|
@ -7,12 +7,12 @@
|
|||
//
|
||||
|
||||
#include "PacketHeaders.h"
|
||||
#include "VoxelAgentData.h"
|
||||
#include "VoxelNodeData.h"
|
||||
#include <cstring>
|
||||
#include <cstdio>
|
||||
|
||||
VoxelAgentData::VoxelAgentData(Agent* owningAgent) :
|
||||
AvatarData(owningAgent),
|
||||
VoxelNodeData::VoxelNodeData(Node* owningNode) :
|
||||
AvatarData(owningNode),
|
||||
_viewSent(false),
|
||||
_voxelPacketAvailableBytes(MAX_VOXEL_PACKET_SIZE),
|
||||
_maxSearchLevel(1),
|
||||
|
@ -25,25 +25,25 @@ VoxelAgentData::VoxelAgentData(Agent* owningAgent) :
|
|||
}
|
||||
|
||||
|
||||
void VoxelAgentData::resetVoxelPacket() {
|
||||
void VoxelNodeData::resetVoxelPacket() {
|
||||
_voxelPacket[0] = getWantColor() ? PACKET_HEADER_VOXEL_DATA : PACKET_HEADER_VOXEL_DATA_MONOCHROME;
|
||||
_voxelPacketAt = &_voxelPacket[1];
|
||||
_voxelPacketAvailableBytes = MAX_VOXEL_PACKET_SIZE - 1;
|
||||
_voxelPacketWaiting = false;
|
||||
}
|
||||
|
||||
void VoxelAgentData::writeToPacket(unsigned char* buffer, int bytes) {
|
||||
void VoxelNodeData::writeToPacket(unsigned char* buffer, int bytes) {
|
||||
memcpy(_voxelPacketAt, buffer, bytes);
|
||||
_voxelPacketAvailableBytes -= bytes;
|
||||
_voxelPacketAt += bytes;
|
||||
_voxelPacketWaiting = true;
|
||||
}
|
||||
|
||||
VoxelAgentData::~VoxelAgentData() {
|
||||
VoxelNodeData::~VoxelNodeData() {
|
||||
delete[] _voxelPacket;
|
||||
}
|
||||
|
||||
bool VoxelAgentData::updateCurrentViewFrustum() {
|
||||
bool VoxelNodeData::updateCurrentViewFrustum() {
|
||||
bool currentViewFrustumChanged = false;
|
||||
ViewFrustum newestViewFrustum;
|
||||
// get position and orientation details from the camera
|
||||
|
@ -65,7 +65,7 @@ bool VoxelAgentData::updateCurrentViewFrustum() {
|
|||
return currentViewFrustumChanged;
|
||||
}
|
||||
|
||||
void VoxelAgentData::updateLastKnownViewFrustum() {
|
||||
void VoxelNodeData::updateLastKnownViewFrustum() {
|
||||
bool frustumChanges = !_lastKnownViewFrustum.matches(_currentViewFrustum);
|
||||
|
||||
if (frustumChanges) {
|
|
@ -1,25 +1,25 @@
|
|||
//
|
||||
// VoxelAgentData.h
|
||||
// VoxelNodeData.h
|
||||
// hifi
|
||||
//
|
||||
// Created by Stephen Birarda on 3/21/13.
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef __hifi__VoxelAgentData__
|
||||
#define __hifi__VoxelAgentData__
|
||||
#ifndef __hifi__VoxelNodeData__
|
||||
#define __hifi__VoxelNodeData__
|
||||
|
||||
#include <iostream>
|
||||
#include <AgentData.h>
|
||||
#include <NodeData.h>
|
||||
#include <AvatarData.h>
|
||||
#include "VoxelNodeBag.h"
|
||||
#include "VoxelConstants.h"
|
||||
#include "CoverageMap.h"
|
||||
|
||||
class VoxelAgentData : public AvatarData {
|
||||
class VoxelNodeData : public AvatarData {
|
||||
public:
|
||||
VoxelAgentData(Agent* owningAgent);
|
||||
~VoxelAgentData();
|
||||
VoxelNodeData(Node* owningNode);
|
||||
~VoxelNodeData();
|
||||
|
||||
void resetVoxelPacket(); // resets voxel packet to after "V" header
|
||||
|
||||
|
@ -51,8 +51,8 @@ public:
|
|||
void setViewSent(bool viewSent) { _viewSent = viewSent; }
|
||||
|
||||
private:
|
||||
VoxelAgentData(const VoxelAgentData &);
|
||||
VoxelAgentData& operator= (const VoxelAgentData&);
|
||||
VoxelNodeData(const VoxelNodeData &);
|
||||
VoxelNodeData& operator= (const VoxelNodeData&);
|
||||
|
||||
bool _viewSent;
|
||||
unsigned char* _voxelPacket;
|
||||
|
@ -66,4 +66,4 @@ private:
|
|||
|
||||
};
|
||||
|
||||
#endif /* defined(__hifi__VoxelAgentData__) */
|
||||
#endif /* defined(__hifi__VoxelNodeData__) */
|
|
@ -11,11 +11,11 @@
|
|||
#include <cstring>
|
||||
#include <cstdio>
|
||||
#include <OctalCode.h>
|
||||
#include <AgentList.h>
|
||||
#include <AgentTypes.h>
|
||||
#include <NodeList.h>
|
||||
#include <NodeTypes.h>
|
||||
#include <EnvironmentData.h>
|
||||
#include <VoxelTree.h>
|
||||
#include "VoxelAgentData.h"
|
||||
#include "VoxelNodeData.h"
|
||||
#include <SharedUtil.h>
|
||||
#include <PacketHeaders.h>
|
||||
#include <SceneUtils.h>
|
||||
|
@ -95,45 +95,45 @@ void randomlyFillVoxelTree(int levelsToGo, VoxelNode *currentRootNode) {
|
|||
}
|
||||
}
|
||||
|
||||
void eraseVoxelTreeAndCleanupAgentVisitData() {
|
||||
void eraseVoxelTreeAndCleanupNodeVisitData() {
|
||||
|
||||
// As our tree to erase all it's voxels
|
||||
::serverTree.eraseAllVoxels();
|
||||
// enumerate the agents clean up their marker nodes
|
||||
for (AgentList::iterator agent = AgentList::getInstance()->begin(); agent != AgentList::getInstance()->end(); agent++) {
|
||||
VoxelAgentData* agentData = (VoxelAgentData*) agent->getLinkedData();
|
||||
if (agentData) {
|
||||
// clean up the agent visit data
|
||||
agentData->nodeBag.deleteAll();
|
||||
// enumerate the nodes clean up their marker nodes
|
||||
for (NodeList::iterator node = NodeList::getInstance()->begin(); node != NodeList::getInstance()->end(); node++) {
|
||||
VoxelNodeData* nodeData = (VoxelNodeData*) node->getLinkedData();
|
||||
if (nodeData) {
|
||||
// clean up the node visit data
|
||||
nodeData->nodeBag.deleteAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Version of voxel distributor that sends each LOD level at a time
|
||||
void resInVoxelDistributor(AgentList* agentList,
|
||||
AgentList::iterator& agent,
|
||||
VoxelAgentData* agentData) {
|
||||
ViewFrustum viewFrustum = agentData->getCurrentViewFrustum();
|
||||
void resInVoxelDistributor(NodeList* nodeList,
|
||||
NodeList::iterator& node,
|
||||
VoxelNodeData* nodeData) {
|
||||
ViewFrustum viewFrustum = nodeData->getCurrentViewFrustum();
|
||||
bool searchReset = false;
|
||||
int searchLoops = 0;
|
||||
int searchLevelWas = agentData->getMaxSearchLevel();
|
||||
int searchLevelWas = nodeData->getMaxSearchLevel();
|
||||
long long start = usecTimestampNow();
|
||||
while (!searchReset && agentData->nodeBag.isEmpty()) {
|
||||
while (!searchReset && nodeData->nodeBag.isEmpty()) {
|
||||
searchLoops++;
|
||||
|
||||
searchLevelWas = agentData->getMaxSearchLevel();
|
||||
int maxLevelReached = serverTree.searchForColoredNodes(agentData->getMaxSearchLevel(), serverTree.rootNode,
|
||||
viewFrustum, agentData->nodeBag);
|
||||
agentData->setMaxLevelReached(maxLevelReached);
|
||||
searchLevelWas = nodeData->getMaxSearchLevel();
|
||||
int maxLevelReached = serverTree.searchForColoredNodes(nodeData->getMaxSearchLevel(), serverTree.rootNode,
|
||||
viewFrustum, nodeData->nodeBag);
|
||||
nodeData->setMaxLevelReached(maxLevelReached);
|
||||
|
||||
// If nothing got added, then we bump our levels.
|
||||
if (agentData->nodeBag.isEmpty()) {
|
||||
if (agentData->getMaxLevelReached() < agentData->getMaxSearchLevel()) {
|
||||
agentData->resetMaxSearchLevel();
|
||||
if (nodeData->nodeBag.isEmpty()) {
|
||||
if (nodeData->getMaxLevelReached() < nodeData->getMaxSearchLevel()) {
|
||||
nodeData->resetMaxSearchLevel();
|
||||
searchReset = true;
|
||||
} else {
|
||||
agentData->incrementMaxSearchLevel();
|
||||
nodeData->incrementMaxSearchLevel();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -143,19 +143,19 @@ void resInVoxelDistributor(AgentList* agentList,
|
|||
if (elapsedmsec > 1000) {
|
||||
int elapsedsec = (end - start)/1000000;
|
||||
printf("WARNING! searchForColoredNodes() took %d seconds to identify %d nodes at level %d in %d loops\n",
|
||||
elapsedsec, agentData->nodeBag.count(), searchLevelWas, searchLoops);
|
||||
elapsedsec, nodeData->nodeBag.count(), searchLevelWas, searchLoops);
|
||||
} else {
|
||||
printf("WARNING! searchForColoredNodes() took %d milliseconds to identify %d nodes at level %d in %d loops\n",
|
||||
elapsedmsec, agentData->nodeBag.count(), searchLevelWas, searchLoops);
|
||||
elapsedmsec, nodeData->nodeBag.count(), searchLevelWas, searchLoops);
|
||||
}
|
||||
} else if (::debugVoxelSending) {
|
||||
printf("searchForColoredNodes() took %d milliseconds to identify %d nodes at level %d in %d loops\n",
|
||||
elapsedmsec, agentData->nodeBag.count(), searchLevelWas, searchLoops);
|
||||
elapsedmsec, nodeData->nodeBag.count(), searchLevelWas, searchLoops);
|
||||
}
|
||||
|
||||
|
||||
// If we have something in our nodeBag, then turn them into packets and send them out...
|
||||
if (!agentData->nodeBag.isEmpty()) {
|
||||
if (!nodeData->nodeBag.isEmpty()) {
|
||||
static unsigned char tempOutputBuffer[MAX_VOXEL_PACKET_SIZE - 1]; // save on allocs by making this static
|
||||
int bytesWritten = 0;
|
||||
int packetsSentThisInterval = 0;
|
||||
|
@ -165,33 +165,33 @@ void resInVoxelDistributor(AgentList* agentList,
|
|||
|
||||
bool shouldSendEnvironments = shouldDo(ENVIRONMENT_SEND_INTERVAL_USECS, VOXEL_SEND_INTERVAL_USECS);
|
||||
while (packetsSentThisInterval < PACKETS_PER_CLIENT_PER_INTERVAL - (shouldSendEnvironments ? 1 : 0)) {
|
||||
if (!agentData->nodeBag.isEmpty()) {
|
||||
VoxelNode* subTree = agentData->nodeBag.extract();
|
||||
if (!nodeData->nodeBag.isEmpty()) {
|
||||
VoxelNode* subTree = nodeData->nodeBag.extract();
|
||||
|
||||
EncodeBitstreamParams params(agentData->getMaxSearchLevel(), &viewFrustum,
|
||||
agentData->getWantColor(), WANT_EXISTS_BITS);
|
||||
EncodeBitstreamParams params(nodeData->getMaxSearchLevel(), &viewFrustum,
|
||||
nodeData->getWantColor(), WANT_EXISTS_BITS);
|
||||
|
||||
bytesWritten = serverTree.encodeTreeBitstream(subTree, &tempOutputBuffer[0], MAX_VOXEL_PACKET_SIZE - 1,
|
||||
agentData->nodeBag, params);
|
||||
nodeData->nodeBag, params);
|
||||
|
||||
if (agentData->getAvailable() >= bytesWritten) {
|
||||
agentData->writeToPacket(&tempOutputBuffer[0], bytesWritten);
|
||||
if (nodeData->getAvailable() >= bytesWritten) {
|
||||
nodeData->writeToPacket(&tempOutputBuffer[0], bytesWritten);
|
||||
} else {
|
||||
agentList->getAgentSocket()->send(agent->getActiveSocket(),
|
||||
agentData->getPacket(), agentData->getPacketLength());
|
||||
trueBytesSent += agentData->getPacketLength();
|
||||
nodeList->getNodeSocket()->send(node->getActiveSocket(),
|
||||
nodeData->getPacket(), nodeData->getPacketLength());
|
||||
trueBytesSent += nodeData->getPacketLength();
|
||||
truePacketsSent++;
|
||||
packetsSentThisInterval++;
|
||||
agentData->resetVoxelPacket();
|
||||
agentData->writeToPacket(&tempOutputBuffer[0], bytesWritten);
|
||||
nodeData->resetVoxelPacket();
|
||||
nodeData->writeToPacket(&tempOutputBuffer[0], bytesWritten);
|
||||
}
|
||||
} else {
|
||||
if (agentData->isPacketWaiting()) {
|
||||
agentList->getAgentSocket()->send(agent->getActiveSocket(),
|
||||
agentData->getPacket(), agentData->getPacketLength());
|
||||
trueBytesSent += agentData->getPacketLength();
|
||||
if (nodeData->isPacketWaiting()) {
|
||||
nodeList->getNodeSocket()->send(node->getActiveSocket(),
|
||||
nodeData->getPacket(), nodeData->getPacketLength());
|
||||
trueBytesSent += nodeData->getPacketLength();
|
||||
truePacketsSent++;
|
||||
agentData->resetVoxelPacket();
|
||||
nodeData->resetVoxelPacket();
|
||||
|
||||
}
|
||||
packetsSentThisInterval = PACKETS_PER_CLIENT_PER_INTERVAL; // done for now, no nodes left
|
||||
|
@ -204,7 +204,7 @@ void resInVoxelDistributor(AgentList* agentList,
|
|||
for (int i = 0; i < sizeof(environmentData) / sizeof(environmentData[0]); i++) {
|
||||
envPacketLength += environmentData[i].getBroadcastData(tempOutputBuffer + envPacketLength);
|
||||
}
|
||||
agentList->getAgentSocket()->send(agent->getActiveSocket(), tempOutputBuffer, envPacketLength);
|
||||
nodeList->getNodeSocket()->send(node->getActiveSocket(), tempOutputBuffer, envPacketLength);
|
||||
trueBytesSent += envPacketLength;
|
||||
truePacketsSent++;
|
||||
}
|
||||
|
@ -214,22 +214,22 @@ void resInVoxelDistributor(AgentList* agentList,
|
|||
if (elapsedmsec > 1000) {
|
||||
int elapsedsec = (end - start)/1000000;
|
||||
printf("WARNING! packetLoop() took %d seconds to generate %d bytes in %d packets at level %d, %d nodes still to send\n",
|
||||
elapsedsec, trueBytesSent, truePacketsSent, searchLevelWas, agentData->nodeBag.count());
|
||||
elapsedsec, trueBytesSent, truePacketsSent, searchLevelWas, nodeData->nodeBag.count());
|
||||
} else {
|
||||
printf("WARNING! packetLoop() took %d milliseconds to generate %d bytes in %d packets at level %d, %d nodes still to send\n",
|
||||
elapsedmsec, trueBytesSent, truePacketsSent, searchLevelWas, agentData->nodeBag.count());
|
||||
elapsedmsec, trueBytesSent, truePacketsSent, searchLevelWas, nodeData->nodeBag.count());
|
||||
}
|
||||
} else if (::debugVoxelSending) {
|
||||
printf("packetLoop() took %d milliseconds to generate %d bytes in %d packets at level %d, %d nodes still to send\n",
|
||||
elapsedmsec, trueBytesSent, truePacketsSent, searchLevelWas, agentData->nodeBag.count());
|
||||
elapsedmsec, trueBytesSent, truePacketsSent, searchLevelWas, nodeData->nodeBag.count());
|
||||
}
|
||||
|
||||
// if during this last pass, we emptied our bag, then we want to move to the next level.
|
||||
if (agentData->nodeBag.isEmpty()) {
|
||||
if (agentData->getMaxLevelReached() < agentData->getMaxSearchLevel()) {
|
||||
agentData->resetMaxSearchLevel();
|
||||
if (nodeData->nodeBag.isEmpty()) {
|
||||
if (nodeData->getMaxLevelReached() < nodeData->getMaxSearchLevel()) {
|
||||
nodeData->resetMaxSearchLevel();
|
||||
} else {
|
||||
agentData->incrementMaxSearchLevel();
|
||||
nodeData->incrementMaxSearchLevel();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -238,9 +238,9 @@ void resInVoxelDistributor(AgentList* agentList,
|
|||
pthread_mutex_t treeLock;
|
||||
|
||||
// Version of voxel distributor that sends the deepest LOD level at once
|
||||
void deepestLevelVoxelDistributor(AgentList* agentList,
|
||||
AgentList::iterator& agent,
|
||||
VoxelAgentData* agentData,
|
||||
void deepestLevelVoxelDistributor(NodeList* nodeList,
|
||||
NodeList::iterator& node,
|
||||
VoxelNodeData* nodeData,
|
||||
bool viewFrustumChanged) {
|
||||
|
||||
|
||||
|
@ -249,20 +249,20 @@ void deepestLevelVoxelDistributor(AgentList* agentList,
|
|||
int maxLevelReached = 0;
|
||||
long long start = usecTimestampNow();
|
||||
|
||||
// FOR NOW... agent tells us if it wants to receive only view frustum deltas
|
||||
bool wantDelta = agentData->getWantDelta();
|
||||
const ViewFrustum* lastViewFrustum = wantDelta ? &agentData->getLastKnownViewFrustum() : NULL;
|
||||
// FOR NOW... node tells us if it wants to receive only view frustum deltas
|
||||
bool wantDelta = nodeData->getWantDelta();
|
||||
const ViewFrustum* lastViewFrustum = wantDelta ? &nodeData->getLastKnownViewFrustum() : NULL;
|
||||
|
||||
if (::debugVoxelSending) {
|
||||
printf("deepestLevelVoxelDistributor() viewFrustumChanged=%s, nodeBag.isEmpty=%s, viewSent=%s\n",
|
||||
debug::valueOf(viewFrustumChanged), debug::valueOf(agentData->nodeBag.isEmpty()),
|
||||
debug::valueOf(agentData->getViewSent())
|
||||
debug::valueOf(viewFrustumChanged), debug::valueOf(nodeData->nodeBag.isEmpty()),
|
||||
debug::valueOf(nodeData->getViewSent())
|
||||
);
|
||||
}
|
||||
|
||||
// If the current view frustum has changed OR we have nothing to send, then search against
|
||||
// the current view frustum for things to send.
|
||||
if (viewFrustumChanged || agentData->nodeBag.isEmpty()) {
|
||||
if (viewFrustumChanged || nodeData->nodeBag.isEmpty()) {
|
||||
|
||||
// For now, we're going to disable the "search for colored nodes" because that strategy doesn't work when we support
|
||||
// deletion of nodes. Instead if we just start at the root we get the correct behavior we want. We are keeping this
|
||||
|
@ -270,16 +270,16 @@ void deepestLevelVoxelDistributor(AgentList* agentList,
|
|||
// helps improve overall bitrate performance.
|
||||
if (::wantSearchForColoredNodes) {
|
||||
// If the bag was empty, then send everything in view, not just the delta
|
||||
maxLevelReached = serverTree.searchForColoredNodes(INT_MAX, serverTree.rootNode, agentData->getCurrentViewFrustum(),
|
||||
agentData->nodeBag, wantDelta, lastViewFrustum);
|
||||
maxLevelReached = serverTree.searchForColoredNodes(INT_MAX, serverTree.rootNode, nodeData->getCurrentViewFrustum(),
|
||||
nodeData->nodeBag, wantDelta, lastViewFrustum);
|
||||
|
||||
// if nothing was found in view, send the root node.
|
||||
if (agentData->nodeBag.isEmpty()){
|
||||
agentData->nodeBag.insert(serverTree.rootNode);
|
||||
if (nodeData->nodeBag.isEmpty()){
|
||||
nodeData->nodeBag.insert(serverTree.rootNode);
|
||||
}
|
||||
agentData->setViewSent(false);
|
||||
nodeData->setViewSent(false);
|
||||
} else {
|
||||
agentData->nodeBag.insert(serverTree.rootNode);
|
||||
nodeData->nodeBag.insert(serverTree.rootNode);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -289,18 +289,18 @@ void deepestLevelVoxelDistributor(AgentList* agentList,
|
|||
if (elapsedmsec > 1000) {
|
||||
int elapsedsec = (end - start)/1000000;
|
||||
printf("WARNING! searchForColoredNodes() took %d seconds to identify %d nodes at level %d\n",
|
||||
elapsedsec, agentData->nodeBag.count(), maxLevelReached);
|
||||
elapsedsec, nodeData->nodeBag.count(), maxLevelReached);
|
||||
} else {
|
||||
printf("WARNING! searchForColoredNodes() took %d milliseconds to identify %d nodes at level %d\n",
|
||||
elapsedmsec, agentData->nodeBag.count(), maxLevelReached);
|
||||
elapsedmsec, nodeData->nodeBag.count(), maxLevelReached);
|
||||
}
|
||||
} else if (::debugVoxelSending) {
|
||||
printf("searchForColoredNodes() took %d milliseconds to identify %d nodes at level %d\n",
|
||||
elapsedmsec, agentData->nodeBag.count(), maxLevelReached);
|
||||
elapsedmsec, nodeData->nodeBag.count(), maxLevelReached);
|
||||
}
|
||||
|
||||
// If we have something in our nodeBag, then turn them into packets and send them out...
|
||||
if (!agentData->nodeBag.isEmpty()) {
|
||||
if (!nodeData->nodeBag.isEmpty()) {
|
||||
static unsigned char tempOutputBuffer[MAX_VOXEL_PACKET_SIZE - 1]; // save on allocs by making this static
|
||||
int bytesWritten = 0;
|
||||
int packetsSentThisInterval = 0;
|
||||
|
@ -310,37 +310,37 @@ void deepestLevelVoxelDistributor(AgentList* agentList,
|
|||
|
||||
bool shouldSendEnvironments = shouldDo(ENVIRONMENT_SEND_INTERVAL_USECS, VOXEL_SEND_INTERVAL_USECS);
|
||||
while (packetsSentThisInterval < PACKETS_PER_CLIENT_PER_INTERVAL - (shouldSendEnvironments ? 1 : 0)) {
|
||||
if (!agentData->nodeBag.isEmpty()) {
|
||||
VoxelNode* subTree = agentData->nodeBag.extract();
|
||||
if (!nodeData->nodeBag.isEmpty()) {
|
||||
VoxelNode* subTree = nodeData->nodeBag.extract();
|
||||
|
||||
bool wantOcclusionCulling = agentData->getWantOcclusionCulling();
|
||||
CoverageMap* coverageMap = wantOcclusionCulling ? &agentData->map : IGNORE_COVERAGE_MAP;
|
||||
bool wantOcclusionCulling = nodeData->getWantOcclusionCulling();
|
||||
CoverageMap* coverageMap = wantOcclusionCulling ? &nodeData->map : IGNORE_COVERAGE_MAP;
|
||||
|
||||
EncodeBitstreamParams params(INT_MAX, &agentData->getCurrentViewFrustum(), agentData->getWantColor(),
|
||||
EncodeBitstreamParams params(INT_MAX, &nodeData->getCurrentViewFrustum(), nodeData->getWantColor(),
|
||||
WANT_EXISTS_BITS, DONT_CHOP, wantDelta, lastViewFrustum,
|
||||
wantOcclusionCulling, coverageMap);
|
||||
|
||||
bytesWritten = serverTree.encodeTreeBitstream(subTree, &tempOutputBuffer[0], MAX_VOXEL_PACKET_SIZE - 1,
|
||||
agentData->nodeBag, params);
|
||||
nodeData->nodeBag, params);
|
||||
|
||||
if (agentData->getAvailable() >= bytesWritten) {
|
||||
agentData->writeToPacket(&tempOutputBuffer[0], bytesWritten);
|
||||
if (nodeData->getAvailable() >= bytesWritten) {
|
||||
nodeData->writeToPacket(&tempOutputBuffer[0], bytesWritten);
|
||||
} else {
|
||||
agentList->getAgentSocket()->send(agent->getActiveSocket(),
|
||||
agentData->getPacket(), agentData->getPacketLength());
|
||||
trueBytesSent += agentData->getPacketLength();
|
||||
nodeList->getNodeSocket()->send(node->getActiveSocket(),
|
||||
nodeData->getPacket(), nodeData->getPacketLength());
|
||||
trueBytesSent += nodeData->getPacketLength();
|
||||
truePacketsSent++;
|
||||
packetsSentThisInterval++;
|
||||
agentData->resetVoxelPacket();
|
||||
agentData->writeToPacket(&tempOutputBuffer[0], bytesWritten);
|
||||
nodeData->resetVoxelPacket();
|
||||
nodeData->writeToPacket(&tempOutputBuffer[0], bytesWritten);
|
||||
}
|
||||
} else {
|
||||
if (agentData->isPacketWaiting()) {
|
||||
agentList->getAgentSocket()->send(agent->getActiveSocket(),
|
||||
agentData->getPacket(), agentData->getPacketLength());
|
||||
trueBytesSent += agentData->getPacketLength();
|
||||
if (nodeData->isPacketWaiting()) {
|
||||
nodeList->getNodeSocket()->send(node->getActiveSocket(),
|
||||
nodeData->getPacket(), nodeData->getPacketLength());
|
||||
trueBytesSent += nodeData->getPacketLength();
|
||||
truePacketsSent++;
|
||||
agentData->resetVoxelPacket();
|
||||
nodeData->resetVoxelPacket();
|
||||
|
||||
}
|
||||
packetsSentThisInterval = PACKETS_PER_CLIENT_PER_INTERVAL; // done for now, no nodes left
|
||||
|
@ -353,7 +353,7 @@ void deepestLevelVoxelDistributor(AgentList* agentList,
|
|||
for (int i = 0; i < sizeof(environmentData) / sizeof(environmentData[0]); i++) {
|
||||
envPacketLength += environmentData[i].getBroadcastData(tempOutputBuffer + envPacketLength);
|
||||
}
|
||||
agentList->getAgentSocket()->send(agent->getActiveSocket(), tempOutputBuffer, envPacketLength);
|
||||
nodeList->getNodeSocket()->send(node->getActiveSocket(), tempOutputBuffer, envPacketLength);
|
||||
trueBytesSent += envPacketLength;
|
||||
truePacketsSent++;
|
||||
}
|
||||
|
@ -364,22 +364,22 @@ void deepestLevelVoxelDistributor(AgentList* agentList,
|
|||
if (elapsedmsec > 1000) {
|
||||
int elapsedsec = (end - start)/1000000;
|
||||
printf("WARNING! packetLoop() took %d seconds to generate %d bytes in %d packets %d nodes still to send\n",
|
||||
elapsedsec, trueBytesSent, truePacketsSent, agentData->nodeBag.count());
|
||||
elapsedsec, trueBytesSent, truePacketsSent, nodeData->nodeBag.count());
|
||||
} else {
|
||||
printf("WARNING! packetLoop() took %d milliseconds to generate %d bytes in %d packets, %d nodes still to send\n",
|
||||
elapsedmsec, trueBytesSent, truePacketsSent, agentData->nodeBag.count());
|
||||
elapsedmsec, trueBytesSent, truePacketsSent, nodeData->nodeBag.count());
|
||||
}
|
||||
} else if (::debugVoxelSending) {
|
||||
printf("packetLoop() took %d milliseconds to generate %d bytes in %d packets, %d nodes still to send\n",
|
||||
elapsedmsec, trueBytesSent, truePacketsSent, agentData->nodeBag.count());
|
||||
elapsedmsec, trueBytesSent, truePacketsSent, nodeData->nodeBag.count());
|
||||
}
|
||||
|
||||
// if after sending packets we've emptied our bag, then we want to remember that we've sent all
|
||||
// the voxels from the current view frustum
|
||||
if (agentData->nodeBag.isEmpty()) {
|
||||
agentData->updateLastKnownViewFrustum();
|
||||
agentData->setViewSent(true);
|
||||
agentData->map.erase();
|
||||
if (nodeData->nodeBag.isEmpty()) {
|
||||
nodeData->updateLastKnownViewFrustum();
|
||||
nodeData->setViewSent(true);
|
||||
nodeData->map.erase();
|
||||
}
|
||||
|
||||
|
||||
|
@ -410,27 +410,27 @@ void persistVoxelsWhenDirty() {
|
|||
|
||||
void *distributeVoxelsToListeners(void *args) {
|
||||
|
||||
AgentList* agentList = AgentList::getInstance();
|
||||
NodeList* nodeList = NodeList::getInstance();
|
||||
timeval lastSendTime;
|
||||
|
||||
while (true) {
|
||||
gettimeofday(&lastSendTime, NULL);
|
||||
|
||||
// enumerate the agents to send 3 packets to each
|
||||
for (AgentList::iterator agent = agentList->begin(); agent != agentList->end(); agent++) {
|
||||
VoxelAgentData* agentData = (VoxelAgentData*) agent->getLinkedData();
|
||||
// enumerate the nodes to send 3 packets to each
|
||||
for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
|
||||
VoxelNodeData* nodeData = (VoxelNodeData*) node->getLinkedData();
|
||||
|
||||
// Sometimes the agent data has not yet been linked, in which case we can't really do anything
|
||||
if (agentData) {
|
||||
bool viewFrustumChanged = agentData->updateCurrentViewFrustum();
|
||||
// Sometimes the node data has not yet been linked, in which case we can't really do anything
|
||||
if (nodeData) {
|
||||
bool viewFrustumChanged = nodeData->updateCurrentViewFrustum();
|
||||
if (::debugVoxelSending) {
|
||||
printf("agentData->updateCurrentViewFrustum() changed=%s\n", debug::valueOf(viewFrustumChanged));
|
||||
printf("nodeData->updateCurrentViewFrustum() changed=%s\n", debug::valueOf(viewFrustumChanged));
|
||||
}
|
||||
|
||||
if (agentData->getWantResIn()) {
|
||||
resInVoxelDistributor(agentList, agent, agentData);
|
||||
if (nodeData->getWantResIn()) {
|
||||
resInVoxelDistributor(nodeList, node, nodeData);
|
||||
} else {
|
||||
deepestLevelVoxelDistributor(agentList, agent, agentData, viewFrustumChanged);
|
||||
deepestLevelVoxelDistributor(nodeList, node, nodeData, viewFrustumChanged);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -448,9 +448,9 @@ void *distributeVoxelsToListeners(void *args) {
|
|||
pthread_exit(0);
|
||||
}
|
||||
|
||||
void attachVoxelAgentDataToAgent(Agent* newAgent) {
|
||||
if (newAgent->getLinkedData() == NULL) {
|
||||
newAgent->setLinkedData(new VoxelAgentData(newAgent));
|
||||
void attachVoxelNodeDataToNode(Node* newNode) {
|
||||
if (newNode->getLinkedData() == NULL) {
|
||||
newNode->setLinkedData(new VoxelNodeData(newNode));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -458,7 +458,7 @@ int main(int argc, const char * argv[]) {
|
|||
|
||||
pthread_mutex_init(&::treeLock, NULL);
|
||||
|
||||
AgentList* agentList = AgentList::createInstance(AGENT_TYPE_VOXEL_SERVER, VOXEL_LISTEN_PORT);
|
||||
NodeList* nodeList = NodeList::createInstance(NODE_TYPE_VOXEL_SERVER, VOXEL_LISTEN_PORT);
|
||||
setvbuf(stdout, NULL, _IOLBF, 0);
|
||||
|
||||
// Handle Local Domain testing with the --local command line
|
||||
|
@ -470,8 +470,8 @@ int main(int argc, const char * argv[]) {
|
|||
sprintf(DOMAIN_IP,"%d.%d.%d.%d", (ip & 0xFF), ((ip >> 8) & 0xFF),((ip >> 16) & 0xFF), ((ip >> 24) & 0xFF));
|
||||
}
|
||||
|
||||
agentList->linkedDataCreateCallback = &attachVoxelAgentDataToAgent;
|
||||
agentList->startSilentAgentRemovalThread();
|
||||
nodeList->linkedDataCreateCallback = &attachVoxelNodeDataToNode;
|
||||
nodeList->startSilentNodeRemovalThread();
|
||||
|
||||
srand((unsigned)time(0));
|
||||
|
||||
|
@ -579,27 +579,27 @@ int main(int argc, const char * argv[]) {
|
|||
pthread_t sendVoxelThread;
|
||||
pthread_create(&sendVoxelThread, NULL, distributeVoxelsToListeners, NULL);
|
||||
|
||||
sockaddr agentPublicAddress;
|
||||
sockaddr nodePublicAddress;
|
||||
|
||||
unsigned char *packetData = new unsigned char[MAX_PACKET_SIZE];
|
||||
ssize_t receivedBytes;
|
||||
|
||||
timeval lastDomainServerCheckIn = {};
|
||||
|
||||
// loop to send to agents requesting data
|
||||
// loop to send to nodes requesting data
|
||||
|
||||
while (true) {
|
||||
|
||||
// send a check in packet to the domain server if DOMAIN_SERVER_CHECK_IN_USECS has elapsed
|
||||
if (usecTimestampNow() - usecTimestamp(&lastDomainServerCheckIn) >= DOMAIN_SERVER_CHECK_IN_USECS) {
|
||||
gettimeofday(&lastDomainServerCheckIn, NULL);
|
||||
AgentList::getInstance()->sendDomainServerCheckIn();
|
||||
NodeList::getInstance()->sendDomainServerCheckIn();
|
||||
}
|
||||
|
||||
// check to see if we need to persist our voxel state
|
||||
persistVoxelsWhenDirty();
|
||||
|
||||
if (agentList->getAgentSocket()->receive(&agentPublicAddress, packetData, &receivedBytes)) {
|
||||
if (nodeList->getNodeSocket()->receive(&nodePublicAddress, packetData, &receivedBytes)) {
|
||||
if (packetData[0] == PACKET_HEADER_SET_VOXEL || packetData[0] == PACKET_HEADER_SET_VOXEL_DESTRUCTIVE) {
|
||||
bool destructive = (packetData[0] == PACKET_HEADER_SET_VOXEL_DESTRUCTIVE);
|
||||
PerformanceWarning warn(::shouldShowAnimationDebug,
|
||||
|
@ -674,7 +674,7 @@ int main(int argc, const char * argv[]) {
|
|||
while (totalLength <= receivedBytes) {
|
||||
if (strcmp(command, ERASE_ALL_COMMAND) == 0) {
|
||||
printf("got Z message == erase all\n");
|
||||
eraseVoxelTreeAndCleanupAgentVisitData();
|
||||
eraseVoxelTreeAndCleanupNodeVisitData();
|
||||
rebroadcast = false;
|
||||
}
|
||||
if (strcmp(command, ADD_SCENE_COMMAND) == 0) {
|
||||
|
@ -689,26 +689,26 @@ int main(int argc, const char * argv[]) {
|
|||
}
|
||||
|
||||
if (rebroadcast) {
|
||||
// Now send this to the connected agents so they can also process these messages
|
||||
printf("rebroadcasting Z message to connected agents... agentList.broadcastToAgents()\n");
|
||||
agentList->broadcastToAgents(packetData, receivedBytes, &AGENT_TYPE_AVATAR, 1);
|
||||
// Now send this to the connected nodes so they can also process these messages
|
||||
printf("rebroadcasting Z message to connected nodes... nodeList.broadcastToNodes()\n");
|
||||
nodeList->broadcastToNodes(packetData, receivedBytes, &NODE_TYPE_AGENT, 1);
|
||||
}
|
||||
}
|
||||
// If we got a PACKET_HEADER_HEAD_DATA, then we're talking to an AGENT_TYPE_AVATAR, and we
|
||||
// need to make sure we have it in our agentList.
|
||||
// If we got a PACKET_HEADER_HEAD_DATA, then we're talking to an NODE_TYPE_AVATAR, and we
|
||||
// need to make sure we have it in our nodeList.
|
||||
if (packetData[0] == PACKET_HEADER_HEAD_DATA) {
|
||||
uint16_t agentID = 0;
|
||||
unpackAgentId(packetData + sizeof(PACKET_HEADER_HEAD_DATA), &agentID);
|
||||
Agent* agent = agentList->addOrUpdateAgent(&agentPublicAddress,
|
||||
&agentPublicAddress,
|
||||
AGENT_TYPE_AVATAR,
|
||||
agentID);
|
||||
uint16_t nodeID = 0;
|
||||
unpackNodeId(packetData + sizeof(PACKET_HEADER_HEAD_DATA), &nodeID);
|
||||
Node* node = nodeList->addOrUpdateNode(&nodePublicAddress,
|
||||
&nodePublicAddress,
|
||||
NODE_TYPE_AGENT,
|
||||
nodeID);
|
||||
|
||||
agentList->updateAgentWithData(agent, packetData, receivedBytes);
|
||||
nodeList->updateNodeWithData(node, packetData, receivedBytes);
|
||||
}
|
||||
// If the packet is a ping, let processAgentData handle it.
|
||||
// If the packet is a ping, let processNodeData handle it.
|
||||
if (packetData[0] == PACKET_HEADER_PING) {
|
||||
agentList->processAgentData(&agentPublicAddress, packetData, receivedBytes);
|
||||
nodeList->processNodeData(&nodePublicAddress, packetData, receivedBytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue