your agents are now nodes

This commit is contained in:
Stephen Birarda 2013-07-03 10:35:09 -07:00
parent 00fa688aba
commit 36c6912de8
42 changed files with 1519 additions and 1519 deletions

View file

@ -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);
}
}

View file

@ -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);
}

View file

@ -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__) */

View file

@ -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;

View file

@ -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);
}
}

View file

@ -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;
}

View file

@ -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);
}

View file

@ -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();
}

View file

@ -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();
}
}
}

View file

@ -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], &currentTime, 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) {

View file

@ -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

View file

@ -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);

View file

@ -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);

View file

@ -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;}

View file

@ -6,7 +6,7 @@
#include <QImage>
#include <AgentList.h>
#include <NodeList.h>
#include "Application.h"
#include "Avatar.h"

View file

@ -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;

View file

@ -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));
}

View file

@ -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;

View file

@ -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();

View file

@ -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!

View file

@ -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();
}

View file

@ -14,7 +14,7 @@
#include "AudioRingBuffer.h"
AudioRingBuffer::AudioRingBuffer(bool isStereo) :
AgentData(NULL),
NodeData(NULL),
_endOfLastWrite(NULL),
_isStarted(false),
_isStereo(isStereo)

View file

@ -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();

View file

@ -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

View file

@ -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; }

View file

@ -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);
}

View file

@ -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() {}

View file

@ -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;
}
}
}

View file

@ -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__) */

View file

@ -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

View file

@ -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);
}
}

View 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);
}

View file

@ -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__) */

View 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() {}

View file

@ -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

View 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;
}
}
}

View 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__) */

View 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

View file

@ -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;

View file

@ -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) {

View file

@ -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__) */

View file

@ -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);
}
}
}