Merge pull request #21 from birarda/19170B

Leo's Avatar Mixer + birarda's AgentData updates
This commit is contained in:
ZappoMan 2013-04-11 10:43:02 -07:00
commit 002d35932e
17 changed files with 503 additions and 140 deletions

View file

@ -3,6 +3,7 @@ cmake_minimum_required(VERSION 2.8)
project(hifi)
add_subdirectory(space)
add_subdirectory(avatar)
add_subdirectory(domain)
add_subdirectory(mixer)
add_subdirectory(voxel)

17
avatar/CMakeLists.txt Normal file
View file

@ -0,0 +1,17 @@
cmake_minimum_required(VERSION 2.8)
project(avatar)
# grab the implemenation and header files
file(GLOB AVATAR_SRCS src/*.cpp src/*.h)
# add the executable
add_executable(avatar ${AVATAR_SRCS})
# link the shared hifi library
include(../LinkHifiShared.cmake)
link_hifi_shared_library(avatar)
# link the threads library
find_package(Threads REQUIRED)
target_link_libraries(avatar ${CMAKE_THREAD_LIBS_INIT})

View file

@ -0,0 +1,116 @@
//
// AvatarAgentData.cpp
// hifi
//
// Created by Stephen Birarda on 4/9/13.
//
//
#include "AvatarAgentData.h"
AvatarAgentData::AvatarAgentData() {
}
AvatarAgentData::~AvatarAgentData() {
}
AvatarAgentData* AvatarAgentData::clone() const {
return new AvatarAgentData(*this);
}
void AvatarAgentData::parseData(void *data, int size) {
char* packetData = (char *)data + 1;
// Extract data from packet
sscanf(packetData,
PACKET_FORMAT,
&_pitch,
&_yaw,
&_roll,
&_headPositionX,
&_headPositionY,
&_headPositionZ,
&_loudness,
&_averageLoudness,
&_handPositionX,
&_handPositionY,
&_handPositionZ);
}
float AvatarAgentData::getPitch() {
return _pitch;
}
float AvatarAgentData::getYaw() {
return _yaw;
}
float AvatarAgentData::getRoll() {
return _roll;
}
float AvatarAgentData::getHeadPositionX() {
return _headPositionX;
}
float AvatarAgentData::getHeadPositionY() {
return _headPositionY;
}
float AvatarAgentData::getHeadPositionZ() {
return _headPositionZ;
}
float AvatarAgentData::getLoudness() {
return _loudness;
}
float AvatarAgentData::getAverageLoudness() {
return _averageLoudness;
}
float AvatarAgentData::getHandPositionX() {
return _handPositionX;
}
float AvatarAgentData::getHandPositionY() {
return _handPositionY;
}
float AvatarAgentData::getHandPositionZ() {
return _handPositionZ;
}
void AvatarAgentData::setPitch(float pitch) {
_pitch = pitch;
}
void AvatarAgentData::setYaw(float yaw) {
_yaw = yaw;
}
void AvatarAgentData::setRoll(float roll) {
_roll = roll;
}
void AvatarAgentData::setHeadPosition(float x, float y, float z) {
_headPositionX = x;
_headPositionY = y;
_headPositionZ = z;
}
void AvatarAgentData::setLoudness(float loudness) {
_loudness = loudness;
}
void AvatarAgentData::setAverageLoudness(float averageLoudness) {
_averageLoudness = averageLoudness;
}
void AvatarAgentData::setHandPosition(float x, float y, float z) {
_handPositionX = x;
_handPositionY = y;
_handPositionZ = z;
}

View file

@ -0,0 +1,58 @@
//
// AvatarAgentData.h
// hifi
//
// Created by Stephen Birarda on 4/9/13.
//
//
#ifndef __hifi__AvatarAgentData__
#define __hifi__AvatarAgentData__
#include <iostream>
#include <AgentData.h>
const char PACKET_FORMAT[] = "%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f";
class AvatarAgentData : public AgentData {
public:
AvatarAgentData();
~AvatarAgentData();
void parseData(void *data, int size);
AvatarAgentData* clone() const;
float getPitch();
void setPitch(float pitch);
float getYaw();
void setYaw(float yaw);
float getRoll();
void setRoll(float roll);
float getHeadPositionX();
float getHeadPositionY();
float getHeadPositionZ();
void setHeadPosition(float x, float y, float z);
float getLoudness();
void setLoudness(float loudness);
float getAverageLoudness();
void setAverageLoudness(float averageLoudness);
float getHandPositionX();
float getHandPositionY();
float getHandPositionZ();
void setHandPosition(float x, float y, float z);
private:
float _pitch;
float _yaw;
float _roll;
float _headPositionX;
float _headPositionY;
float _headPositionZ;
float _loudness;
float _averageLoudness;
float _handPositionX;
float _handPositionY;
float _handPositionZ;
};
#endif /* defined(__hifi__AvatarAgentData__) */

131
avatar/src/main.cpp Normal file
View file

@ -0,0 +1,131 @@
//
// main.cpp
// Avatar Mixer
//
// Created by Leonardo Murillo on 03/25/13.
// 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.
//
//
#include <iostream>
#include <math.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <pthread.h>
#include <errno.h>
#include <fstream>
#include <limits>
#include <sys/time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <AgentList.h>
#include <SharedUtil.h>
#include <PacketHeaders.h>
#include <AgentTypes.h>
#include <StdDev.h>
#include <UDPSocket.h>
#include "AvatarAgentData.h"
const int AVATAR_LISTEN_PORT = 55444;
const unsigned short BROADCAST_INTERVAL_USECS = 20 * 1000 * 1000;
AgentList agentList(AGENT_TYPE_AVATAR_MIXER, AVATAR_LISTEN_PORT);
unsigned char *addAgentToBroadcastPacket(unsigned char *currentPosition, Agent *agentToAdd) {
currentPosition += packSocket(currentPosition, agentToAdd->getPublicSocket());
AvatarAgentData *agentData = (AvatarAgentData *)agentToAdd->getLinkedData();
int bytesWritten = sprintf((char *)currentPosition,
PACKET_FORMAT,
agentData->getPitch(),
agentData->getYaw(),
agentData->getRoll(),
agentData->getHeadPositionX(),
agentData->getHeadPositionY(),
agentData->getHeadPositionZ(),
agentData->getLoudness(),
agentData->getAverageLoudness(),
agentData->getHandPositionX(),
agentData->getHandPositionY(),
agentData->getHandPositionZ());
currentPosition += bytesWritten;
return currentPosition;
}
void attachAvatarDataToAgent(Agent *newAgent) {
if (newAgent->getLinkedData() == NULL) {
newAgent->setLinkedData(new AvatarAgentData());
}
}
int main(int argc, char* argv[])
{
setvbuf(stdout, NULL, _IOLBF, 0);
agentList.linkedDataCreateCallback = attachAvatarDataToAgent;
agentList.startDomainServerCheckInThread();
agentList.startSilentAgentRemovalThread();
agentList.startPingUnknownAgentsThread();
sockaddr *agentAddress = new sockaddr;
char *packetData = new char[MAX_PACKET_SIZE];
ssize_t receivedBytes = 0;
unsigned char *broadcastPacket = new unsigned char[MAX_PACKET_SIZE];
*broadcastPacket = PACKET_HEADER_AVATAR_SERVER;
unsigned char* currentBufferPosition = NULL;
int agentIndex = 0;
while (true) {
if (agentList.getAgentSocket().receive(agentAddress, packetData, &receivedBytes)) {
switch (packetData[0]) {
case PACKET_HEADER_HEAD_DATA:
// this is positional data from an agent
agentList.updateAgentWithData(agentAddress, (void *)packetData, receivedBytes);
currentBufferPosition = broadcastPacket + 1;
agentIndex = 0;
// send back a packet with other active agent data to this agent
for (std::vector<Agent>::iterator avatarAgent = agentList.getAgents().begin();
avatarAgent != agentList.getAgents().end();
avatarAgent++) {
if (avatarAgent->getLinkedData() != NULL
&& agentIndex != agentList.indexOfMatchingAgent(agentAddress)) {
currentBufferPosition = addAgentToBroadcastPacket(currentBufferPosition, &*avatarAgent);
}
agentIndex++;
}
agentList.getAgentSocket().send(agentAddress,
broadcastPacket,
currentBufferPosition - broadcastPacket);
break;
default:
// hand this off to the AgentList
agentList.processAgentData(agentAddress, (void *)packetData, receivedBytes);
break;
}
}
}
agentList.stopDomainServerCheckInThread();
agentList.stopSilentAgentRemovalThread();
agentList.stopPingUnknownAgentsThread();
return 0;
}

View file

@ -127,9 +127,12 @@ int main(int argc, const char * argv[])
currentBufferPos = broadcastPacket + 1;
startPointer = currentBufferPos;
for(std::vector<Agent>::iterator agent = agentList.getAgents().begin(); agent != agentList.getAgents().end(); agent++) {
for(std::vector<Agent>::iterator agent = agentList.getAgents().begin();
agent != agentList.getAgents().end();
agent++) {
if (DEBUG_TO_SELF || !agent->matches((sockaddr *)&agentPublicAddress, (sockaddr *)&agentLocalAddress, agentType)) {
if (DEBUG_TO_SELF ||
!agent->matches((sockaddr *)&agentPublicAddress, (sockaddr *)&agentLocalAddress, agentType)) {
if (strchr(SOLO_AGENT_TYPES_STRING, (int) agent->getType()) == NULL) {
// this is an agent of which there can be multiple, just add them to the packet
currentBufferPos = addAgentToBroadcastPacket(currentBufferPos, &(*agent));
@ -155,7 +158,9 @@ int main(int argc, const char * argv[])
}
if ((packetBytesWithoutLeadingChar = (currentBufferPos - startPointer))) {
agentList.getAgentSocket().send((sockaddr *)&agentPublicAddress, broadcastPacket, packetBytesWithoutLeadingChar + 1);
agentList.getAgentSocket().send((sockaddr *)&agentPublicAddress,
broadcastPacket,
packetBytesWithoutLeadingChar + 1);
}
}
}

View file

@ -21,8 +21,7 @@ const float DEFAULT_Y = -1.5;
const float DEFAULT_Z = 2.0;
const float DEFAULT_TRANSMITTER_HZ = 60.0;
Hand::Hand(glm::vec3 initcolor)
{
Hand::Hand(glm::vec3 initcolor) {
color = initcolor;
reset();
noise = 0.0; //0.2;
@ -51,8 +50,7 @@ Hand::Hand(const Hand &otherHand) {
renderPointer = otherHand.renderPointer;
}
void Hand::reset()
{
void Hand::reset() {
position.x = DEFAULT_X;
position.y = DEFAULT_Y;
position.z = DEFAULT_Z;
@ -64,8 +62,7 @@ void Hand::reset()
transmitterHz = DEFAULT_TRANSMITTER_HZ;
}
void Hand::render(int isMine)
{
void Hand::render(int isMine) {
const float POINTER_LENGTH = 20.0;
glPushMatrix();
glTranslatef(position.x, position.y, position.z);
@ -89,22 +86,7 @@ void Hand::render(int isMine)
glutSolidCube(1.0);
glPopMatrix();
}
glPopMatrix();
if (1) {
// Render debug info from the transmitter
/*
glPushMatrix();
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
//gluOrtho2D(0, WIDTH, HEIGHT, 0);
glDisable(GL_DEPTH_TEST);
glDisable(GL_LIGHTING);
glPopMatrix();
*/
}
glPopMatrix();
}
void Hand::addAngularVelocity (float pRate, float yRate, float rRate) {
@ -159,8 +141,7 @@ void Hand::processTransmitterData(char *packetData, int numBytes) {
}
void Hand::simulate(float deltaTime)
{
void Hand::simulate(float deltaTime) {
const float ANGULAR_SPRING_CONSTANT = 0.25;
const float ANGULAR_DAMPING_COEFFICIENT = 5*2.0f*powf(ANGULAR_SPRING_CONSTANT,0.5f);
const float LINEAR_SPRING_CONSTANT = 100;

View file

@ -200,21 +200,6 @@ timeval timerStart, timerEnd;
timeval lastTimeIdle;
double elapsedTime;
#ifdef MARKER_CAPTURE
/*** Marker Capture ***/
#define MARKER_CAPTURE_INTERVAL 1
MarkerCapture marker_capturer(CV_CAP_ANY); // Create a new marker capturer, attached to any valid camera.
MarkerAcquisitionView marker_acq_view(&marker_capturer);
bool marker_capture_enabled = true;
bool marker_capture_display = true;
IplImage* marker_capture_frame;
IplImage* marker_capture_blob_frame;
pthread_mutex_t frame_lock;
#endif
// Every second, check the frame rates and other stuff
void Timer(int extra)
{
@ -229,9 +214,6 @@ void Timer(int extra)
glutTimerFunc(1000,Timer,0);
gettimeofday(&timerStart, NULL);
// Ping the agents we can see
agentList.pingAgents();
// if we haven't detected gyros, check for them now
if (!serialPort.active) {
serialPort.pair();
@ -478,11 +460,12 @@ void simulateHead(float frametime)
myAvatar.setAverageLoudness(averageLoudness);
#endif
// Send my streaming head data to agents that are nearby and need to see it!
const int MAX_BROADCAST_STRING = 200;
char broadcast_string[MAX_BROADCAST_STRING];
int broadcast_bytes = myAvatar.getBroadcastData(broadcast_string);
agentList.broadcastToAgents(broadcast_string, broadcast_bytes,AgentList::AGENTS_OF_TYPE_VOXEL_AND_INTERFACE);
// Send my stream of head/hand data to the avatar mixer and voxel server
char broadcastString[200];
int broadcastBytes = myAvatar.getBroadcastData(broadcastString);
const char broadcastReceivers[2] = {AGENT_TYPE_VOXEL, AGENT_TYPE_AVATAR_MIXER};
agentList.broadcastToAgents(broadcastString, broadcastBytes, broadcastReceivers, 2);
// If I'm in paint mode, send a voxel out to VOXEL server agents.
if (::paintOn) {
@ -501,8 +484,8 @@ void simulateHead(float frametime)
::paintingVoxel.y >= 0.0 && ::paintingVoxel.y <= 1.0 &&
::paintingVoxel.z >= 0.0 && ::paintingVoxel.z <= 1.0) {
if (createVoxelEditMessage(PACKET_HEADER_SET_VOXEL,0,1,&::paintingVoxel,bufferOut,sizeOut)){
agentList.broadcastToAgents((char*)bufferOut, sizeOut,AgentList::AGENTS_OF_TYPE_VOXEL);
if (createVoxelEditMessage(PACKET_HEADER_SET_VOXEL, 0, 1, &::paintingVoxel, bufferOut, sizeOut)){
agentList.broadcastToAgents((char*)bufferOut, sizeOut, &AGENT_TYPE_VOXEL, 1);
delete bufferOut;
}
}
@ -1023,15 +1006,15 @@ void testPointToVoxel()
void sendVoxelServerEraseAll() {
char message[100];
sprintf(message,"%c%s",'Z',"erase all");
int messageSize = strlen(message)+1;
::agentList.broadcastToAgents(message, messageSize,AgentList::AGENTS_OF_TYPE_VOXEL);
int messageSize = strlen(message) + 1;
::agentList.broadcastToAgents(message, messageSize, &AGENT_TYPE_VOXEL, 1);
}
void sendVoxelServerAddScene() {
char message[100];
sprintf(message,"%c%s",'Z',"add scene");
int messageSize = strlen(message)+1;
::agentList.broadcastToAgents(message, messageSize,AgentList::AGENTS_OF_TYPE_VOXEL);
int messageSize = strlen(message) + 1;
::agentList.broadcastToAgents(message, messageSize, &AGENT_TYPE_VOXEL, 1);
}
void shiftPaintingColor()
@ -1207,9 +1190,7 @@ void key(unsigned char k, int x, int y)
if (k == '.') addRandomSphere(wantColorRandomizer);
}
//
// Receive packets from other agents/servers and decide what to do with them!
//
void *networkReceive(void *args)
{
sockaddr senderAddress;
@ -1221,19 +1202,26 @@ void *networkReceive(void *args)
packetCount++;
bytesCount += bytesReceived;
if (incomingPacket[0] == PACKET_HEADER_TRANSMITTER_DATA) {
// Pass everything but transmitter data to the agent list
myAvatar.hand->processTransmitterData(incomingPacket, bytesReceived);
} else if (incomingPacket[0] == PACKET_HEADER_VOXEL_DATA ||
incomingPacket[0] == PACKET_HEADER_Z_COMMAND ||
incomingPacket[0] == PACKET_HEADER_ERASE_VOXEL) {
voxels.parseData(incomingPacket, bytesReceived);
} else {
agentList.processAgentData(&senderAddress, incomingPacket, bytesReceived);
switch (incomingPacket[0]) {
case PACKET_HEADER_TRANSMITTER_DATA:
myAvatar.hand->processTransmitterData(incomingPacket, bytesReceived);
break;
case PACKET_HEADER_VOXEL_DATA:
case PACKET_HEADER_Z_COMMAND:
case PACKET_HEADER_ERASE_VOXEL:
voxels.parseData(incomingPacket, bytesReceived);
break;
case PACKET_HEADER_HEAD_DATA:
agentList.processBulkAgentData(&senderAddress, incomingPacket, bytesReceived, sizeof(float) * 11);
break;
default:
agentList.processAgentData(&senderAddress, incomingPacket, bytesReceived);
break;
}
}
}
delete[] incomingPacket;
pthread_exit(0);
return NULL;
}
@ -1401,9 +1389,10 @@ int main(int argc, const char * argv[])
int wsaresult = WSAStartup( MAKEWORD(2,2), &WsaData );
#endif
// start the thread which checks for silent agents
// start the agentList threads
agentList.startSilentAgentRemovalThread();
agentList.startDomainServerCheckInThread();
agentList.startPingUnknownAgentsThread();
glutInit(&argc, (char**)argv);
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);

View file

@ -51,7 +51,7 @@ namespace starfield {
return false;
}
fprintf(stderr, "Stars.cpp: read %d stars, rendering %ld\n",
_valRecordsRead, _ptrVertices->size());
_valRecordsRead, _ptrVertices->size());
return true;
}

View file

@ -27,7 +27,7 @@ namespace starfield {
InputVertex(float azimuth, float altitude, unsigned color) {
_valColor = (color >> 16 & 0xffu) | (color & 0xff00u) |
(color << 16 & 0xff0000u) | 0xff000000u;
(color << 16 & 0xff0000u) | 0xff000000u;
azimuth = angleConvert<Degrees,Radians>(azimuth);
altitude = angleConvert<Degrees,Radians>(altitude);

View file

@ -61,7 +61,7 @@ const int AGENT_LOOPBACK_MODIFIER = 307;
const int LOOPBACK_SANITY_CHECK = 0;
AgentList agentList(AGENT_TYPE_MIXER, MIXER_LISTEN_PORT);
AgentList agentList(AGENT_TYPE_AUDIO_MIXER, MIXER_LISTEN_PORT);
StDev stdev;
void plateauAdditionOfSamples(int16_t &mixSample, int16_t sampleToAdd) {

View file

@ -67,7 +67,7 @@ Agent::Agent(const Agent &otherAgent) {
linkedData = NULL;
}
deleteMutex = otherAgent.deleteMutex;
pthread_mutex_init(&deleteMutex, NULL);
}
Agent& Agent::operator=(Agent otherAgent) {
@ -83,7 +83,6 @@ void Agent::swap(Agent &first, Agent &second) {
swap(first.type, second.type);
swap(first.linkedData, second.linkedData);
swap(first.agentId, second.agentId);
swap(first.deleteMutex, second.deleteMutex);
}
Agent::~Agent() {
@ -100,7 +99,8 @@ char Agent::getType() const {
const char* AGENT_TYPE_NAME_DOMAIN = "Domain";
const char* AGENT_TYPE_NAME_VOXEL = "Voxel Server";
const char* AGENT_TYPE_NAME_INTERFACE = "Client Interface";
const char* AGENT_TYPE_NAME_MIXER = "Audio Mixer";
const char* AGENT_TYPE_NAME_AUDIO_MIXER = "Audio Mixer";
const char* AGENT_TYPE_NAME_AVATAR_MIXER = "Avatar Mixer";
const char* AGENT_TYPE_NAME_UNKNOWN = "Unknown";
const char* Agent::getTypeName() const {
@ -115,9 +115,12 @@ const char* Agent::getTypeName() const {
case AGENT_TYPE_INTERFACE:
name = AGENT_TYPE_NAME_INTERFACE;
break;
case AGENT_TYPE_MIXER:
name = AGENT_TYPE_NAME_MIXER;
case AGENT_TYPE_AUDIO_MIXER:
name = AGENT_TYPE_NAME_AUDIO_MIXER;
break;
case AGENT_TYPE_AVATAR_MIXER:
name = AGENT_TYPE_NAME_AVATAR_MIXER;
break;
}
return name;
}

View file

@ -28,6 +28,7 @@ const int DOMAINSERVER_PORT = 40102;
bool silentAgentThreadStopFlag = false;
bool domainServerCheckinStopFlag = false;
bool pingUnknownAgentThreadStopFlag = false;
pthread_mutex_t vectorChangeMutex = PTHREAD_MUTEX_INITIALIZER;
int unpackAgentId(unsigned char *packedData, uint16_t *agentId) {
@ -50,6 +51,7 @@ AgentList::~AgentList() {
// stop the spawned threads, if they were started
stopSilentAgentRemovalThread();
stopDomainServerCheckInThread();
stopPingUnknownAgentsThread();
}
std::vector<Agent>& AgentList::getAgents() {
@ -71,48 +73,71 @@ unsigned int AgentList::getSocketListenPort() {
void AgentList::processAgentData(sockaddr *senderAddress, void *packetData, size_t dataBytes) {
switch (((char *)packetData)[0]) {
case PACKET_HEADER_DOMAIN: {
// list of agents from domain server
updateList((unsigned char *)packetData, dataBytes);
break;
}
case PACKET_HEADER_HEAD_DATA: {
// head data from another agent
updateAgentWithData(senderAddress, packetData, dataBytes);
break;
}
case PACKET_HEADER_PING: {
// ping from another agent
//std::cout << "Got ping from " << inet_ntoa(((sockaddr_in *)senderAddress)->sin_addr) << "\n";
agentSocket.send(senderAddress, &PACKET_HEADER_PING_REPLY, 1);
break;
}
case PACKET_HEADER_PING_REPLY: {
// ping reply from another agent
//std::cout << "Got ping reply from " << inet_ntoa(((sockaddr_in *)senderAddress)->sin_addr) << "\n";
handlePingReply(senderAddress);
break;
}
}
}
void AgentList::processBulkAgentData(sockaddr *senderAddress, void *packetData, int numTotalBytes, int numBytesPerAgent) {
// find the avatar mixer in our agent list and update the lastRecvTime from it
int bulkSendAgentIndex = indexOfMatchingAgent(senderAddress);
if (bulkSendAgentIndex >= 0) {
Agent *bulkSendAgent = &agents[bulkSendAgentIndex];
bulkSendAgent->setLastRecvTimeUsecs(usecTimestampNow());
}
unsigned char *startPosition = (unsigned char *)packetData;
unsigned char *currentPosition = startPosition + 1;
unsigned char *packetHolder = new unsigned char[numBytesPerAgent + 1];
packetHolder[0] = PACKET_HEADER_HEAD_DATA;
uint16_t agentID = -1;
while ((currentPosition - startPosition) < numTotalBytes) {
currentPosition += unpackAgentId(currentPosition, &agentID);
memcpy(packetHolder + 1, currentPosition, numBytesPerAgent);
int matchingAgentIndex = indexOfMatchingAgent(agentID);
if (matchingAgentIndex >= 0) {
updateAgentWithData(&agents[matchingAgentIndex], packetHolder, numBytesPerAgent + 1);
}
currentPosition += numBytesPerAgent;
}
delete[] packetHolder;
}
void AgentList::updateAgentWithData(sockaddr *senderAddress, void *packetData, size_t dataBytes) {
// find the agent by the sockaddr
int agentIndex = indexOfMatchingAgent(senderAddress);
if (agentIndex != -1) {
Agent *matchingAgent = &agents[agentIndex];
matchingAgent->setLastRecvTimeUsecs(usecTimestampNow());
if (matchingAgent->getLinkedData() == NULL) {
if (linkedDataCreateCallback != NULL) {
linkedDataCreateCallback(matchingAgent);
}
}
matchingAgent->getLinkedData()->parseData(packetData, dataBytes);
updateAgentWithData(&agents[agentIndex], packetData, dataBytes);
}
}
void AgentList::updateAgentWithData(Agent *agent, void *packetData, int dataBytes) {
agent->setLastRecvTimeUsecs(usecTimestampNow());
if (agent->getLinkedData() == NULL) {
if (linkedDataCreateCallback != NULL) {
linkedDataCreateCallback(agent);
}
}
agent->getLinkedData()->parseData(packetData, dataBytes);
}
int AgentList::indexOfMatchingAgent(sockaddr *senderAddress) {
@ -125,6 +150,16 @@ int AgentList::indexOfMatchingAgent(sockaddr *senderAddress) {
return -1;
}
int AgentList::indexOfMatchingAgent(uint16_t agentID) {
for(std::vector<Agent>::iterator agent = agents.begin(); agent != agents.end(); agent++) {
if (agent->getActiveSocket() != NULL && agent->getAgentId() == agentID) {
return agent - agents.begin();
}
}
return -1;
}
uint16_t AgentList::getLastAgentId() {
return lastAgentId;
}
@ -176,12 +211,12 @@ bool AgentList::addOrUpdateAgent(sockaddr *publicSocket, sockaddr *localSocket,
Agent newAgent = Agent(publicSocket, localSocket, agentType, agentId);
if (socketMatch(publicSocket, localSocket)) {
// likely debugging scenario with DS + agent on local network
// likely debugging scenario with two agents on local network
// set the agent active right away
newAgent.activatePublicSocket();
}
if (newAgent.getType() == AGENT_TYPE_MIXER && audioMixerSocketUpdate != NULL) {
if (newAgent.getType() == AGENT_TYPE_AUDIO_MIXER && audioMixerSocketUpdate != NULL) {
// this is an audio mixer
// for now that means we need to tell the audio class
// to use the local socket information the domain server gave us
@ -200,7 +235,7 @@ bool AgentList::addOrUpdateAgent(sockaddr *publicSocket, sockaddr *localSocket,
return true;
} else {
if (agent->getType() == AGENT_TYPE_MIXER || agent->getType() == AGENT_TYPE_VOXEL) {
if (agent->getType() == AGENT_TYPE_AUDIO_MIXER || agent->getType() == AGENT_TYPE_VOXEL) {
// 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->setLastRecvTimeUsecs(usecTimestampNow());
@ -211,54 +246,72 @@ bool AgentList::addOrUpdateAgent(sockaddr *publicSocket, sockaddr *localSocket,
}
}
// XXXBHG - do we want to move these?
const char* AgentList::AGENTS_OF_TYPE_VOXEL = "V";
const char* AgentList::AGENTS_OF_TYPE_INTERFACE = "I";
const char* AgentList::AGENTS_OF_TYPE_VOXEL_AND_INTERFACE = "VI";
void AgentList::broadcastToAgents(char *broadcastData, size_t dataBytes,const char* agentTypes) {
void AgentList::broadcastToAgents(char *broadcastData, size_t dataBytes, const char* agentTypes, int numAgentTypes) {
for(std::vector<Agent>::iterator agent = agents.begin(); agent != agents.end(); agent++) {
// only send to the AgentTypes we are asked to send to.
if (agent->getActiveSocket() != NULL && strchr(agentTypes,agent->getType())) {
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);
}
}
}
void AgentList::pingAgents() {
char payload[1];
*payload = PACKET_HEADER_PING;
for(std::vector<Agent>::iterator agent = agents.begin(); agent != agents.end(); agent++) {
if (agent->getType() == AGENT_TYPE_INTERFACE) {
if (agent->getActiveSocket() != NULL) {
// we know which socket is good for this agent, send there
agentSocket.send(agent->getActiveSocket(), payload, 1);
} else {
// ping both of the sockets for the agent so we can figure out
// which socket we can use
agentSocket.send(agent->getPublicSocket(), payload, 1);
agentSocket.send(agent->getLocalSocket(), payload, 1);
}
}
}
}
void AgentList::handlePingReply(sockaddr *agentAddress) {
for(std::vector<Agent>::iterator agent = agents.begin(); agent != agents.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();
std::cout << "Activated public socket for agent " << &*agent << "\n";
break;
} else if (socketMatch(agent->getLocalSocket(), agentAddress)) {
agent->activateLocalSocket();
std::cout << "Activated local socket for agent " << &*agent << "\n";
break;
}
}
}
void *pingUnknownAgents(void *args) {
AgentList *agentList = (AgentList *)args;
const int PING_INTERVAL_USECS = 1 * 1000000;
timeval lastSend;
while (!pingUnknownAgentThreadStopFlag) {
gettimeofday(&lastSend, NULL);
for(std::vector<Agent>::iterator agent = agentList->getAgents().begin();
agent != agentList->getAgents().end();
agent++) {
if (agent->getActiveSocket() == NULL) {
// 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);
}
}
double 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) {
std::vector<Agent> *agents = (std::vector<Agent> *)args;
double checkTimeUSecs, sleepTime;
@ -289,7 +342,6 @@ void *removeSilentAgents(void *args) {
}
}
sleepTime = AGENT_SILENCE_THRESHOLD_USECS - (usecTimestampNow() - checkTimeUSecs);
#ifdef _WIN32
Sleep( static_cast<int>(1000.0f*sleepTime) );
@ -313,6 +365,8 @@ void AgentList::stopSilentAgentRemovalThread() {
void *checkInWithDomainServer(void *args) {
const int DOMAIN_SERVER_CHECK_IN_USECS = 1 * 1000000;
AgentList *parentAgentList = (AgentList *)args;
timeval lastSend;
@ -343,7 +397,7 @@ void *checkInWithDomainServer(void *args) {
parentAgentList->getAgentSocket().send(DOMAIN_IP, DOMAINSERVER_PORT, output, 7);
double usecToSleep = 1000000 - (usecTimestampNow() - usecTimestamp(&lastSend));
double usecToSleep = DOMAIN_SERVER_CHECK_IN_USECS - (usecTimestampNow() - usecTimestamp(&lastSend));
if (usecToSleep > 0) {
usleep(usecToSleep);

View file

@ -28,7 +28,6 @@ extern char DOMAIN_HOSTNAME[];
extern char DOMAIN_IP[100]; // IP Address will be re-set by lookup on startup
extern const int DOMAINSERVER_PORT;
class AgentList {
UDPSocket agentSocket;
@ -38,6 +37,7 @@ class AgentList {
uint16_t lastAgentId;
pthread_t removeSilentAgentsThread;
pthread_t checkInWithDomainServerThread;
pthread_t pingUnknownAgentsThread;
void handlePingReply(sockaddr *agentAddress);
public:
@ -50,15 +50,23 @@ public:
std::vector<Agent>& getAgents();
UDPSocket& getAgentSocket();
int updateList(unsigned char *packetData, size_t dataBytes);
int indexOfMatchingAgent(sockaddr *senderAddress);
uint16_t getLastAgentId();
void increaseAgentId();
int updateList(unsigned char *packetData, size_t dataBytes);
int indexOfMatchingAgent(sockaddr *senderAddress);
int indexOfMatchingAgent(uint16_t agentID);
bool addOrUpdateAgent(sockaddr *publicSocket, sockaddr *localSocket, char agentType, uint16_t agentId);
void processAgentData(sockaddr *senderAddress, void *packetData, size_t dataBytes);
void processBulkAgentData(sockaddr *senderAddress, void *packetData, int numTotalBytes, int numBytesPerAgent);
void updateAgentWithData(sockaddr *senderAddress, void *packetData, size_t dataBytes);
void broadcastToAgents(char *broadcastData, size_t dataBytes, const char* agentTypes);
void pingAgents();
void updateAgentWithData(Agent *agent, void *packetData, int dataBytes);
void broadcastToAgents(char *broadcastData, size_t dataBytes, const char* agentTypes, int numAgentTypes);
char getOwnerType();
unsigned int getSocketListenPort();
@ -66,10 +74,8 @@ public:
void stopSilentAgentRemovalThread();
void startDomainServerCheckInThread();
void stopDomainServerCheckInThread();
static const char* AGENTS_OF_TYPE_VOXEL;
static const char* AGENTS_OF_TYPE_INTERFACE;
static const char* AGENTS_OF_TYPE_VOXEL_AND_INTERFACE;
void startPingUnknownAgentsThread();
void stopPingUnknownAgentsThread();
};
int unpackAgentId(unsigned char *packedData, uint16_t *agentId);

View file

@ -21,6 +21,7 @@
const char AGENT_TYPE_DOMAIN = 'D';
const char AGENT_TYPE_VOXEL = 'V';
const char AGENT_TYPE_INTERFACE = 'I'; // could also be injector???
const char AGENT_TYPE_MIXER = 'M';
const char AGENT_TYPE_AUDIO_MIXER = 'M';
const char AGENT_TYPE_AVATAR_MIXER = 'W';
#endif

View file

@ -21,6 +21,7 @@ const char PACKET_HEADER_INJECT_AUDIO = 'I';
const char PACKET_HEADER_SET_VOXEL = 'S';
const char PACKET_HEADER_ERASE_VOXEL = 'E';
const char PACKET_HEADER_VOXEL_DATA = 'V';
const char PACKET_HEADER_AVATAR_SERVER = 'X';
const char PACKET_HEADER_TRANSMITTER_DATA = 't';
#endif

View file

@ -345,7 +345,7 @@ int main(int argc, const char * argv[])
// Now send this to the connected agents so they know to delete
printf("rebroadcasting delete voxel message to connected agents... agentList.broadcastToAgents()\n");
agentList.broadcastToAgents(packetData,receivedBytes,AgentList::AGENTS_OF_TYPE_INTERFACE);
agentList.broadcastToAgents(packetData,receivedBytes, &AGENT_TYPE_INTERFACE, 1);
}
if (packetData[0] == PACKET_HEADER_Z_COMMAND) {
@ -373,7 +373,7 @@ int main(int argc, const char * argv[])
// 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,AgentList::AGENTS_OF_TYPE_INTERFACE);
agentList.broadcastToAgents(packetData,receivedBytes, &AGENT_TYPE_INTERFACE, 1);
}
// If we got a PACKET_HEADER_HEAD_DATA, then we're talking to an AGENT_TYPE_INTERFACE, and we
// need to make sure we have it in our agentList.