From f4a1c405fc6307be96448aaf20c1fa8f169cf2fc Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 22 Feb 2013 10:13:12 -0800 Subject: [PATCH 01/11] remove useless cast, activeSocket is a sockaddr --- shared/src/AgentList.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/shared/src/AgentList.cpp b/shared/src/AgentList.cpp index fb16bac54f..8c145053cd 100644 --- a/shared/src/AgentList.cpp +++ b/shared/src/AgentList.cpp @@ -150,7 +150,7 @@ void AgentList::broadcastToAgents(char *broadcastData, size_t dataBytes) { // until the Audio class uses the AgentList if (agent->activeSocket != NULL && agent->type == 'I') { // we know which socket is good for this agent, send there - agentSocket.send((sockaddr *)agent->activeSocket, broadcastData, dataBytes); + agentSocket.send(agent->activeSocket, broadcastData, dataBytes); } } } @@ -163,7 +163,7 @@ void AgentList::pingAgents() { if (agent->type == 'I') { if (agent->activeSocket != NULL) { // we know which socket is good for this agent, send there - agentSocket.send((sockaddr *)agent->activeSocket, payload, 1); + agentSocket.send(agent->activeSocket, payload, 1); } else { // ping both of the sockets for the agent so we can figure out // which socket we can use From 41259f9ae0bacf7b8abda5f4948a3a49e554aeeb Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Fri, 22 Feb 2013 12:10:29 -0800 Subject: [PATCH 02/11] Changed Hand to be a floating 'paddle' in front of the head --- interface/src/Hand.cpp | 47 +++++++++++++++++------------------------- interface/src/Hand.h | 16 +++++--------- interface/src/Head.cpp | 17 +++++++++++---- interface/src/Head.h | 6 +++++- interface/src/main.cpp | 28 ------------------------- 5 files changed, 42 insertions(+), 72 deletions(-) diff --git a/interface/src/Hand.cpp b/interface/src/Hand.cpp index 92ec070217..d7f9cf1847 100644 --- a/interface/src/Hand.cpp +++ b/interface/src/Hand.cpp @@ -8,33 +8,29 @@ #include "Hand.h" -const float DEFAULT_X = 0.0; -const float DEFAULT_Y = 0.0; -const float DEFAULT_Z = -7.0; +const float PHI = 1.618; -Hand::Hand(float initradius, glm::vec3 initcolor) +const float DEFAULT_X = 0; +const float DEFAULT_Y = -1.5; +const float DEFAULT_Z = 2.0; + +Hand::Hand(glm::vec3 initcolor) { color = initcolor; - radius = initradius; reset(); - noise = 0; + noise = 0.2; + scale.x = 0.07; + scale.y = scale.x * 5.0; + scale.z = scale.y * 2.0; } void Hand::render() { - glEnable(GL_DEPTH_TEST); glPushMatrix(); - glLoadIdentity(); - if (isColliding) glColor3f(1,0,0); - else glColor3f(color.x, color.y, color.z); - glBegin(GL_LINES); - glVertex3f(-0.05, -0.5, 0.0); - glVertex3f(position.x, position.y, position.z); - glVertex3f(0.05, -0.5, 0.0); - glVertex3f(position.x, position.y, position.z); - glEnd(); glTranslatef(position.x, position.y, position.z); - glutSolidSphere(radius, 15, 15); + glColor3f(color.x, color.y, color.z); + glScalef(scale.x, scale.y, scale.z); + glutSolidSphere(1.5, 20, 20); glPopMatrix(); } @@ -43,22 +39,17 @@ void Hand::reset() position.x = DEFAULT_X; position.y = DEFAULT_Y; position.z = DEFAULT_Z; + setTarget(position); velocity.x = velocity.y = velocity.z = 0; - isColliding = false; } void Hand::simulate(float deltaTime) { - position += velocity*deltaTime; - - velocity *= (1.f - 4.0*deltaTime); - - if ((noise) && (randFloat() < 0.1)) - { - velocity.x += (randFloat() - 0.5)*noise; - velocity.y += (randFloat() - 0.5)*noise; - velocity.z += (randFloat() - 0.5)*noise; - + // If noise, add wandering movement + if (noise && (randFloat() < 0.1)) { + position += noise * glm::vec3(randFloat() - 0.5, randFloat() - 0.5, randFloat() - 0.5); } + // Decay position of hand toward target + position -= deltaTime*(position - target); } \ No newline at end of file diff --git a/interface/src/Hand.h b/interface/src/Hand.h index 694fb5eb03..9f64343673 100644 --- a/interface/src/Hand.h +++ b/interface/src/Hand.h @@ -16,26 +16,20 @@ #include "world.h" #include "InterfaceConfig.h" -const float RADIUS_RANGE = 10.0; - class Hand { public: - Hand(float initradius, glm::vec3 color); + Hand(glm::vec3 color); void simulate (float deltaTime); void render (); void reset (); void setNoise (float mag) { noise = mag; }; - void addVel (glm::vec3 add) { velocity += add; }; + void addVel (glm::vec3 v) { velocity += v; }; glm::vec3 getPos() { return position; }; - void setPos(glm::vec3 newpos) { position = newpos; }; - float getRadius() { return radius; }; - void setRadius(float newradius) { radius = newradius; }; - void setColliding(bool newcollide) { isColliding = newcollide; }; + void setPos(glm::vec3 p) { position = p; }; + void setTarget(glm::vec3 t) { target = t; }; private: - glm::vec3 position, velocity, color; + glm::vec3 position, target, velocity, color, scale; float noise; - float radius; - bool isColliding; }; diff --git a/interface/src/Head.cpp b/interface/src/Head.cpp index 31a388c1d7..90033af565 100644 --- a/interface/src/Head.cpp +++ b/interface/src/Head.cpp @@ -57,6 +57,7 @@ Head::Head() renderYaw = 0.0; renderPitch = 0.0; setNoise(0); + hand = new Hand(glm::vec3(skinColor[0], skinColor[1], skinColor[2])); } Head::~Head() { @@ -205,6 +206,7 @@ void Head::simulate(float deltaTime) } } + hand->simulate(deltaTime); } @@ -216,27 +218,34 @@ void Head::render(int faceToFace, float * myLocation) glm::vec3 cameraHead(myLocation[0], myLocation[1], myLocation[2]); float distanceToCamera = glm::distance(cameraHead, position); - //std::cout << distanceToCamera << "\n"; // Don't render a head if it is really close to your location, because that is your own head! if ((distanceToCamera > 1.0) || faceToFace) { glEnable(GL_DEPTH_TEST); glPushMatrix(); + glScalef(scale, scale, scale); glTranslatef(leanSideways, 0.f, leanForward); - glRotatef(Yaw, 0, 1, 0); + glRotatef(Yaw, 0, 1, 0); + + hand->render(); + glRotatef(Pitch, 1, 0, 0); glRotatef(Roll, 0, 0, 1); + // Overall scale of head if (faceToFace) glScalef(1.5, 2.0, 2.0); else glScalef(0.75, 1.0, 1.0); glColor3fv(skinColor); - + + // Head - glutSolidSphere(1, 30, 30); + glutSolidSphere(1, 30, 30); + + //std::cout << distanceToCamera << "\n"; // Ears glPushMatrix(); diff --git a/interface/src/Head.h b/interface/src/Head.h index 7dc8ef7588..038f37bfc5 100644 --- a/interface/src/Head.h +++ b/interface/src/Head.h @@ -13,6 +13,8 @@ #include "AgentData.h" #include "Field.h" #include "world.h" +#include "Head.h" +#include "Hand.h" #include "InterfaceConfig.h" #include "SerialInterface.h" @@ -95,7 +97,9 @@ class Head : public AgentData { int eyeContact; eyeContactTargets eyeContactTarget; void readSensors(); - float renderYaw, renderPitch; // Pitch from view frustum when this is own head. + float renderYaw, renderPitch; // Pitch from view frustum when this is own head. + + Hand * hand; }; #endif \ No newline at end of file diff --git a/interface/src/main.cpp b/interface/src/main.cpp index 0f96ceb951..c4846becc4 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -84,8 +84,6 @@ Oscilloscope audioScope(512,200,true); #define HAND_RADIUS 0.25 // Radius of in-world 'hand' of you Head myHead; // The rendered head of oneself -Hand myHand(HAND_RADIUS, - glm::vec3(0,1,1)); // My hand (used to manipulate things in world) glm::vec3 box(WORLD_SIZE,WORLD_SIZE,WORLD_SIZE); ParticleSystem balls(0, @@ -138,7 +136,6 @@ float noise = 1.0; // Overall magnitude scaling for random noi int step_on = 0; int display_levels = 0; int display_head = 0; -int display_hand = 0; int display_field = 0; int display_head_mouse = 1; // Display sample mouse pointer controlled by head movement @@ -332,7 +329,6 @@ void init(void) if (noise_on) { - myHand.setNoise(noise); myHead.setNoise(noise); } @@ -383,7 +379,6 @@ void reset_sensors() head_lean_y = HEIGHT/2; myHead.reset(); - myHand.reset(); if (serialPort.active) { serialPort.resetTrailingAverages(); @@ -414,20 +409,6 @@ void update_pos(float frametime) head_mouse_y = max(head_mouse_y, 0); head_mouse_y = min(head_mouse_y, HEIGHT); - // Update hand/manipulator location for measured forces from serial channel - /* - const float MIN_HAND_ACCEL = 30.0; - const float HAND_FORCE_SCALE = 0.5; - glm::vec3 hand_accel(-(avg_adc_channels[6] - adc_channels[6]), - -(avg_adc_channels[7] - adc_channels[7]), - -(avg_adc_channels[5] - adc_channels[5])); - - if (glm::length(hand_accel) > MIN_HAND_ACCEL) - { - myHand.addVel(frametime*hand_accel*HAND_FORCE_SCALE); - } - */ - // Update render direction (pitch/yaw) based on measured gyro rates const int MIN_YAW_RATE = 100; const float YAW_SENSITIVITY = 0.08; @@ -505,9 +486,6 @@ void update_pos(float frametime) location[0] += fwd_vec[2]*-lateral_vel; location[2] += fwd_vec[0]*lateral_vel; - // Update manipulator objects with object with current location - balls.updateHand(myHead.getPos() + myHand.getPos(), glm::vec3(0,0,0), myHand.getRadius()); - // Update own head data myHead.setRenderYaw(myHead.getRenderYaw() + render_yaw_rate); myHead.setRenderPitch(render_pitch); @@ -594,8 +572,6 @@ void display(void) } } - if (display_hand) myHand.render(); - if (!display_head) balls.render(); // Render the world box @@ -715,18 +691,15 @@ void key(unsigned char k, int x, int y) noise_on = !noise_on; // Toggle noise if (noise_on) { - myHand.setNoise(noise); myHead.setNoise(noise); } else { - myHand.setNoise(0); myHead.setNoise(0); } } if (k == 'h') display_head = !display_head; - if (k == 'b') display_hand = !display_hand; if (k == 'm') head_mirror = !head_mirror; if (k == 'f') display_field = !display_field; @@ -789,7 +762,6 @@ void idle(void) if (simulate_on) { field.simulate(1.f/FPS); myHead.simulate(1.f/FPS); - myHand.simulate(1.f/FPS); balls.simulate(1.f/FPS); cloud.simulate(1.f/FPS); lattice.simulate(1.f/FPS); From 014fdcc618a057b4a43e5cbcd5d041608d82d2eb Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Fri, 22 Feb 2013 12:20:01 -0800 Subject: [PATCH 03/11] Tweaked hand 'length' --- interface/src/Hand.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/interface/src/Hand.cpp b/interface/src/Hand.cpp index d7f9cf1847..c7e0c57094 100644 --- a/interface/src/Hand.cpp +++ b/interface/src/Hand.cpp @@ -21,7 +21,7 @@ Hand::Hand(glm::vec3 initcolor) noise = 0.2; scale.x = 0.07; scale.y = scale.x * 5.0; - scale.z = scale.y * 2.0; + scale.z = scale.y * 1.0; } void Hand::render() @@ -46,8 +46,8 @@ void Hand::reset() void Hand::simulate(float deltaTime) { // If noise, add wandering movement - if (noise && (randFloat() < 0.1)) { - position += noise * glm::vec3(randFloat() - 0.5, randFloat() - 0.5, randFloat() - 0.5); + if (noise) { + position += noise * 0.1f * glm::vec3(randFloat() - 0.5, randFloat() - 0.5, randFloat() - 0.5); } // Decay position of hand toward target position -= deltaTime*(position - target); From 200982dddc987d12d4074b1afdb200e7eb73c74c Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 22 Feb 2013 12:20:16 -0800 Subject: [PATCH 04/11] fix for UDPSocket receive crash in Audio class and main.cpp --- interface/src/Audio.cpp | 8 +++++--- interface/src/Audio.h | 3 +++ interface/src/main.cpp | 8 +++++--- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index e8dd588a5f..61f9b56bae 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -44,6 +44,7 @@ const char EC2_WEST_MIXER[] = "54.241.92.53"; const int AUDIO_UDP_LISTEN_PORT = 55444; int starve_counter = 0; +bool stopAudioReceiveThread = false; StDev stdev; @@ -202,7 +203,7 @@ void *receiveAudioViaUDP(void *args) { delete[] filename; } - while (true) { + while (!stopAudioReceiveThread) { if (sharedAudioData->audioSocket->receive((void *)receivedData, &receivedBytes)) { bool firstSample = (currentReceiveTime.tv_sec == 0); @@ -284,8 +285,6 @@ Audio::Audio(Oscilloscope * s) audioData->audioSocket = new UDPSocket(AUDIO_UDP_LISTEN_PORT); audioData->ringBuffer = new AudioRingBuffer(RING_BUFFER_SIZE_SAMPLES); - pthread_t audioReceiveThread; - AudioRecThreadStruct threadArgs; threadArgs.sharedAudioData = audioData; @@ -435,6 +434,9 @@ bool Audio::terminate () logFile.close(); } + stopAudioReceiveThread = true; + pthread_join(audioReceiveThread, NULL); + return true; error: diff --git a/interface/src/Audio.h b/interface/src/Audio.h index c9f2e55cfc..7f1fa9143f 100644 --- a/interface/src/Audio.h +++ b/interface/src/Audio.h @@ -41,6 +41,9 @@ private: // audio stream handle PaStream *stream; + // audio receive thread + pthread_t audioReceiveThread; + // give access to AudioData class from audioCallback friend int audioCallback (const void*, void*, unsigned long, const PaStreamCallbackTimeInfo*, PaStreamCallbackFlags, void*); }; diff --git a/interface/src/main.cpp b/interface/src/main.cpp index 0f96ceb951..235f6be8f0 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -59,6 +59,8 @@ char DOMAIN_IP[100] = ""; // IP Address will be used first if not empty stri const int DOMAINSERVER_PORT = 40102; AgentList agentList; +pthread_t networkReceiveThread; +bool stopAgentDataReceiveThread = false; // For testing, add milliseconds of delay for received UDP packets int packetcount = 0; @@ -360,6 +362,8 @@ void terminate () { //close(serial_fd); audio.terminate(); + stopAgentDataReceiveThread = true; + pthread_join(networkReceiveThread, NULL); exit(EXIT_SUCCESS); } @@ -763,7 +767,7 @@ void *networkReceive(void *args) ssize_t bytesReceived; char *incomingPacket = new char[MAX_PACKET_SIZE]; - while (true) { + while (!stopAgentDataReceiveThread) { if (agentList.getAgentSocket()->receive(&senderAddress, incomingPacket, &bytesReceived)) { packetcount++; bytescount += bytesReceived; @@ -938,7 +942,6 @@ int main(int argc, char** argv) agentList.audioMixerSocketUpdate = &audioMixerUpdate; // create thread for receipt of data via UDP - pthread_t networkReceiveThread; pthread_create(&networkReceiveThread, NULL, networkReceive, NULL); glutInit(&argc, argv); @@ -969,7 +972,6 @@ int main(int argc, char** argv) glutMainLoop(); - pthread_join(networkReceiveThread, NULL); ::terminate(); return EXIT_SUCCESS; } From 777a00db3e65e7dff6478083eab31503cc08651c Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Fri, 22 Feb 2013 12:28:27 -0800 Subject: [PATCH 05/11] Adding hand data to head broadcast packet. --- interface/src/Head.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/interface/src/Head.cpp b/interface/src/Head.cpp index 90033af565..b9fec9c48d 100644 --- a/interface/src/Head.cpp +++ b/interface/src/Head.cpp @@ -345,18 +345,23 @@ void Head::render(int faceToFace, float * myLocation) int Head::getBroadcastData(char* data) { // Copy data for transmission to the buffer, return length of data - sprintf(data, "H%f,%f,%f,%f,%f,%f,%f,%f", getRenderPitch() + Pitch, -getRenderYaw() + 180 -Yaw, Roll, + sprintf(data, "H%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f", + getRenderPitch() + Pitch, -getRenderYaw() + 180 -Yaw, Roll, position.x + leanSideways, position.y, position.z + leanForward, - loudness, averageLoudness); + loudness, averageLoudness, + hand->getPos().x, hand->getPos().y, hand->getPos().z); return strlen(data); } void Head::parseData(void *data, int size) { // parse head data for this agent - sscanf((char *)data, "H%f,%f,%f,%f,%f,%f,%f,%f", + glm::vec3 handPos(0,0,0); + sscanf((char *)data, "H%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f", &Pitch, &Yaw, &Roll, &position.x, &position.y, &position.z, - &loudness, &averageLoudness); + &loudness, &averageLoudness, + &handPos.x, &handPos.y, &handPos.z); + if (glm::length(handPos) > 0.0) hand->setPos(handPos); } void Head::SetNewHeadTarget(float pitch, float yaw) From 0453445b134cc80cf1dab0bfc1d425f95e378994 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Fri, 22 Feb 2013 12:47:28 -0800 Subject: [PATCH 06/11] Render own manipulator hand in front of camera --- interface/src/Head.cpp | 24 ++++++++++++------------ interface/src/main.cpp | 14 ++++++-------- 2 files changed, 18 insertions(+), 20 deletions(-) diff --git a/interface/src/Head.cpp b/interface/src/Head.cpp index b9fec9c48d..78ea7f950c 100644 --- a/interface/src/Head.cpp +++ b/interface/src/Head.cpp @@ -218,19 +218,19 @@ void Head::render(int faceToFace, float * myLocation) glm::vec3 cameraHead(myLocation[0], myLocation[1], myLocation[2]); float distanceToCamera = glm::distance(cameraHead, position); + // Always render own hand, but don't render head unless showing face2face + glEnable(GL_DEPTH_TEST); + glPushMatrix(); + + glScalef(scale, scale, scale); + glTranslatef(leanSideways, 0.f, leanForward); + + glRotatef(Yaw, 0, 1, 0); + + hand->render(); // Don't render a head if it is really close to your location, because that is your own head! if ((distanceToCamera > 1.0) || faceToFace) { - glEnable(GL_DEPTH_TEST); - glPushMatrix(); - - - glScalef(scale, scale, scale); - glTranslatef(leanSideways, 0.f, leanForward); - - glRotatef(Yaw, 0, 1, 0); - - hand->render(); glRotatef(Pitch, 1, 0, 0); glRotatef(Roll, 0, 0, 1); @@ -335,9 +335,9 @@ void Head::render(int faceToFace, float * myLocation) glutSolidSphere(PupilSize, 15, 15); glPopMatrix(); - glPopMatrix(); + } - + glPopMatrix(); } // Transmit data to agents requesting it diff --git a/interface/src/main.cpp b/interface/src/main.cpp index c4846becc4..f7b3106b4b 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -578,14 +578,12 @@ void display(void) if (!display_head && stats_on) render_world_box(); // Render my own head - - if (display_head) { - glPushMatrix(); - glLoadIdentity(); - glTranslatef(0.f, 0.f, -7.f); - myHead.render(1, &location[0]); - glPopMatrix(); - } + glPushMatrix(); + glLoadIdentity(); + glTranslatef(0.f, 0.f, -7.f); + myHead.render(display_head, &location[0]); + glPopMatrix(); + //glm::vec3 test(0.5, 0.5, 0.5); //render_vector(&test); From 345ec8b9387fdf98a1b9b28fc95ef221a611cc56 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 22 Feb 2013 13:37:57 -0800 Subject: [PATCH 07/11] fix threaded socket joins so that socket has timeout on blocking receive --- interface/src/Audio.cpp | 17 +++++++++-------- interface/src/main.cpp | 7 ++++--- shared/src/UDPSocket.cpp | 6 ++++++ 3 files changed, 19 insertions(+), 11 deletions(-) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 61f9b56bae..b433b2a199 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -44,9 +44,8 @@ const char EC2_WEST_MIXER[] = "54.241.92.53"; const int AUDIO_UDP_LISTEN_PORT = 55444; int starve_counter = 0; -bool stopAudioReceiveThread = false; - StDev stdev; +bool stopAudioReceiveThread = false; #define LOG_SAMPLE_DELAY 1 @@ -263,6 +262,8 @@ void *receiveAudioViaUDP(void *args) { } } } + + pthread_exit(0); } /** @@ -306,6 +307,7 @@ Audio::Audio(Oscilloscope * s) Pa_StartStream(stream); if (paError != paNoError) goto error; + return; error: @@ -420,6 +422,9 @@ void Audio::render(int screenWidth, int screenHeight) */ bool Audio::terminate () { + stopAudioReceiveThread = true; + pthread_join(audioReceiveThread, NULL); + if (initialized) { initialized = false; @@ -428,14 +433,10 @@ bool Audio::terminate () paError = Pa_Terminate(); if (paError != paNoError) goto error; - - delete audioData; - - logFile.close(); } - stopAudioReceiveThread = true; - pthread_join(audioReceiveThread, NULL); + logFile.close(); + delete audioData; return true; diff --git a/interface/src/main.cpp b/interface/src/main.cpp index 235f6be8f0..a030d51c6e 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -60,7 +60,7 @@ const int DOMAINSERVER_PORT = 40102; AgentList agentList; pthread_t networkReceiveThread; -bool stopAgentDataReceiveThread = false; +bool stopNetworkReceiveThread = false; // For testing, add milliseconds of delay for received UDP packets int packetcount = 0; @@ -362,8 +362,9 @@ void terminate () { //close(serial_fd); audio.terminate(); - stopAgentDataReceiveThread = true; + stopNetworkReceiveThread = true; pthread_join(networkReceiveThread, NULL); + exit(EXIT_SUCCESS); } @@ -767,7 +768,7 @@ void *networkReceive(void *args) ssize_t bytesReceived; char *incomingPacket = new char[MAX_PACKET_SIZE]; - while (!stopAgentDataReceiveThread) { + while (!stopNetworkReceiveThread) { if (agentList.getAgentSocket()->receive(&senderAddress, incomingPacket, &bytesReceived)) { packetcount++; bytescount += bytesReceived; diff --git a/shared/src/UDPSocket.cpp b/shared/src/UDPSocket.cpp index fd6102f367..ec4c63803e 100644 --- a/shared/src/UDPSocket.cpp +++ b/shared/src/UDPSocket.cpp @@ -81,6 +81,12 @@ UDPSocket::UDPSocket(int listeningPort) { return; } + // set timeout on socket recieve to 0.5 seconds + struct timeval tv; + tv.tv_sec = 0; + tv.tv_usec = 500000; + setsockopt(handle, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof tv); + printf("Created UDP socket listening on port %d.\n", listeningPort); } From 5d2cba0b2ad2539f977f74acd9f3b6d29470306f Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 22 Feb 2013 13:38:33 -0800 Subject: [PATCH 08/11] add silent agent removal to AgentList class --- interface/src/main.cpp | 3 +++ shared/src/Agent.cpp | 6 ++--- shared/src/Agent.h | 1 + shared/src/AgentList.cpp | 54 ++++++++++++++++++++++++++++++++++++--- shared/src/AgentList.h | 8 +++++- shared/src/SharedUtil.cpp | 19 ++++++++++++++ shared/src/SharedUtil.h | 18 +++++++++++++ 7 files changed, 102 insertions(+), 7 deletions(-) create mode 100644 shared/src/SharedUtil.cpp create mode 100644 shared/src/SharedUtil.h diff --git a/interface/src/main.cpp b/interface/src/main.cpp index a030d51c6e..ad3865d4c0 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -942,6 +942,9 @@ int main(int argc, char** argv) agentList.linkedDataCreateCallback = &attachNewHeadToAgent; agentList.audioMixerSocketUpdate = &audioMixerUpdate; + // start the thread which checks for silent agents + agentList.startSilentAgentRemovalThread(); + // create thread for receipt of data via UDP pthread_create(&networkReceiveThread, NULL, networkReceive, NULL); diff --git a/shared/src/Agent.cpp b/shared/src/Agent.cpp index 2eef5c4423..a8a6984a09 100644 --- a/shared/src/Agent.cpp +++ b/shared/src/Agent.cpp @@ -10,10 +10,9 @@ #include #include #include "UDPSocket.h" +#include "SharedUtil.h" -Agent::Agent() { - -} +Agent::Agent() {} Agent::Agent(sockaddr *agentPublicSocket, sockaddr *agentLocalSocket, char agentType) { publicSocket = new sockaddr; @@ -23,6 +22,7 @@ Agent::Agent(sockaddr *agentPublicSocket, sockaddr *agentLocalSocket, char agent memcpy(localSocket, agentLocalSocket, sizeof(sockaddr)); type = agentType; + lastRecvTimeUsecs = usecTimestampNow(); activeSocket = NULL; linkedData = NULL; diff --git a/shared/src/Agent.h b/shared/src/Agent.h index 59ec0e612c..efcebc3b05 100644 --- a/shared/src/Agent.h +++ b/shared/src/Agent.h @@ -28,6 +28,7 @@ class Agent { char type; timeval pingStarted; int pingMsecs; + double lastRecvTimeUsecs; bool isSelf; AgentData *linkedData; diff --git a/shared/src/AgentList.cpp b/shared/src/AgentList.cpp index 8c145053cd..d11976349f 100644 --- a/shared/src/AgentList.cpp +++ b/shared/src/AgentList.cpp @@ -8,6 +8,11 @@ #include "AgentList.h" #include +#include +#include "SharedUtil.h" + +bool stopAgentRemovalThread = false; +pthread_mutex_t vectorChangeMutex = PTHREAD_MUTEX_INITIALIZER; AgentList::AgentList() : agentSocket(AGENT_SOCKET_LISTEN_PORT) { linkedDataCreateCallback = NULL; @@ -15,7 +20,12 @@ AgentList::AgentList() : agentSocket(AGENT_SOCKET_LISTEN_PORT) { } AgentList::AgentList(int socketListenPort) : agentSocket(socketListenPort) { - + linkedDataCreateCallback = NULL; + audioMixerSocketUpdate = NULL; +} + +AgentList::~AgentList() { + stopSilentAgentRemovalThread(); } UDPSocket * AgentList::getAgentSocket() { @@ -59,6 +69,8 @@ void AgentList::updateAgentWithData(sockaddr *senderAddress, void *packetData, s if (agentIndex != -1) { Agent *matchingAgent = &agents[agentIndex]; + matchingAgent->lastRecvTimeUsecs = usecTimestampNow(); + if (matchingAgent->linkedData == NULL) { if (linkedDataCreateCallback != NULL) { linkedDataCreateCallback(matchingAgent); @@ -135,7 +147,9 @@ bool AgentList::addOrUpdateAgent(sockaddr *publicSocket, sockaddr *localSocket, std::cout << "Added agent - " << &newAgent << "\n"; - agents.push_back(newAgent); + pthread_mutex_lock(&vectorChangeMutex); + agents.push_back(newAgent); + pthread_mutex_unlock(&vectorChangeMutex); return true; } else { @@ -155,7 +169,6 @@ void AgentList::broadcastToAgents(char *broadcastData, size_t dataBytes) { } } - void AgentList::pingAgents() { char payload[] = "P"; @@ -193,4 +206,39 @@ void AgentList::handlePingReply(sockaddr *agentAddress) { break; } } +} + +void *removeSilentAgents(void *args) { + std::vector *agents = (std::vector *)args; + double checkTimeUSecs, sleepTime; + + while (!stopAgentRemovalThread) { + checkTimeUSecs = usecTimestampNow(); + + for(std::vector::iterator agent = agents->begin(); agent != agents->end();) { + if ((checkTimeUSecs - agent->lastRecvTimeUsecs) > AGENT_SILENCE_THRESHOLD_USECS) { + std::cout << "Killing agent " << &(*agent) << "\n"; + pthread_mutex_lock(&vectorChangeMutex); + agent = agents->erase(agent); + pthread_mutex_unlock(&vectorChangeMutex); + } else { + agent++; + } + } + + + sleepTime = AGENT_SILENCE_THRESHOLD_USECS - (usecTimestampNow() - checkTimeUSecs); + usleep(sleepTime); + } + + pthread_exit(0); +} + +void AgentList::startSilentAgentRemovalThread() { + pthread_create(&removeSilentAgentsThread, NULL, removeSilentAgents, (void *)&agents); +} + +void AgentList::stopSilentAgentRemovalThread() { + stopAgentRemovalThread = true; + pthread_join(removeSilentAgentsThread, NULL); } \ No newline at end of file diff --git a/shared/src/AgentList.h b/shared/src/AgentList.h index c04a18bf8c..399340b841 100644 --- a/shared/src/AgentList.h +++ b/shared/src/AgentList.h @@ -15,11 +15,13 @@ #include "UDPSocket.h" const unsigned short AGENT_SOCKET_LISTEN_PORT = 40103; +const int AGENT_SILENCE_THRESHOLD_USECS = 2 * 1000000; class AgentList { public: AgentList(); AgentList(int socketListenPort); + ~AgentList(); std::vector agents; void(*linkedDataCreateCallback)(Agent *); void(*audioMixerSocketUpdate)(in_addr_t, in_port_t); @@ -30,12 +32,16 @@ class AgentList { bool addOrUpdateAgent(sockaddr *publicSocket, sockaddr *localSocket, char agentType); void processAgentData(sockaddr *senderAddress, void *packetData, size_t dataBytes); void broadcastToAgents(char *broadcastData, size_t dataBytes); + void sendToAgent(Agent *destAgent, void *packetData, size_t dataBytes); void pingAgents(); + void startSilentAgentRemovalThread(); + void stopSilentAgentRemovalThread(); private: - UDPSocket agentSocket; int indexOfMatchingAgent(sockaddr *senderAddress); void updateAgentWithData(sockaddr *senderAddress, void *packetData, size_t dataBytes); void handlePingReply(sockaddr *agentAddress); + UDPSocket agentSocket; + pthread_t removeSilentAgentsThread; }; #endif /* defined(__hifi__AgentList__) */ diff --git a/shared/src/SharedUtil.cpp b/shared/src/SharedUtil.cpp new file mode 100644 index 0000000000..5880b8919a --- /dev/null +++ b/shared/src/SharedUtil.cpp @@ -0,0 +1,19 @@ +// +// SharedUtil.cpp +// hifi +// +// Created by Stephen Birarda on 2/22/13. +// +// + +#include "SharedUtil.h" + +double usecTimestamp(timeval *time) { + return (time->tv_sec * 1000000.0); +} + +double usecTimestampNow() { + timeval now; + gettimeofday(&now, NULL); + return (now.tv_sec * 1000000.0); +} \ No newline at end of file diff --git a/shared/src/SharedUtil.h b/shared/src/SharedUtil.h new file mode 100644 index 0000000000..c8b88a8a55 --- /dev/null +++ b/shared/src/SharedUtil.h @@ -0,0 +1,18 @@ +// +// SharedUtil.h +// hifi +// +// Created by Stephen Birarda on 2/22/13. +// +// + +#ifndef __hifi__SharedUtil__ +#define __hifi__SharedUtil__ + +#include +#include + +double usecTimestamp(timeval *time); +double usecTimestampNow(); + +#endif /* defined(__hifi__SharedUtil__) */ From 92f5c88ab77c66091ecc99513647917978ec0ed7 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 22 Feb 2013 13:43:29 -0800 Subject: [PATCH 09/11] have domain server remove dead agents from list --- domain/src/main.cpp | 4 +++- shared/src/AgentList.cpp | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/domain/src/main.cpp b/domain/src/main.cpp index 0914b4db68..4784a72ac0 100644 --- a/domain/src/main.cpp +++ b/domain/src/main.cpp @@ -67,7 +67,8 @@ int main(int argc, const char * argv[]) sockaddr_in agentPublicAddress, agentLocalAddress; agentLocalAddress.sin_family = AF_INET; - + + agentList.startSilentAgentRemovalThread(); while (true) { if (agentList.getAgentSocket()->receive((sockaddr *)&agentPublicAddress, packetData, &receivedBytes)) { @@ -83,6 +84,7 @@ int main(int argc, const char * argv[]) } } } + return 0; } diff --git a/shared/src/AgentList.cpp b/shared/src/AgentList.cpp index d11976349f..d743353820 100644 --- a/shared/src/AgentList.cpp +++ b/shared/src/AgentList.cpp @@ -153,7 +153,8 @@ bool AgentList::addOrUpdateAgent(sockaddr *publicSocket, sockaddr *localSocket, return true; } else { - // we had this agent already + // we had this agent already, just update receive timestamp + agent->lastRecvTimeUsecs = usecTimestampNow(); return false; } } From 9c60ac991897daa08b6824db4c6ccd5b5c5ccd76 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 22 Feb 2013 13:47:25 -0800 Subject: [PATCH 10/11] shared library should link pthreads on UNIX --- shared/CMakeLists.txt | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/shared/CMakeLists.txt b/shared/CMakeLists.txt index afe855d47e..e03926f641 100644 --- a/shared/CMakeLists.txt +++ b/shared/CMakeLists.txt @@ -7,4 +7,11 @@ file(GLOB HIFI_SHARED_SRCS src/*.h src/*.cpp) # create a library and set the property so it can be referenced later add_library(HifiShared ${HIFI_SHARED_SRCS}) -set(HIFI_SHARED_LIBRARY HifiShared) \ No newline at end of file +set(HIFI_SHARED_LIBRARY HifiShared) + +# link required libraries on UNIX +if (UNIX AND NOT APPLE) + find_package(Threads REQUIRED) + + target_link_libraries(HifiShared ${CMAKE_THREAD_LIBS_INIT}) +endif (UNIX AND NOT APPLE) \ No newline at end of file From 6a16d6e3bb6bec237308c167ff1fd174181bb7a7 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 22 Feb 2013 14:54:19 -0800 Subject: [PATCH 11/11] clean up agent killing/re-adding for interface and domain --- domain/src/main.cpp | 44 +++++++++++++++++++++++----------------- interface/src/main.cpp | 2 +- shared/src/Agent.cpp | 1 + shared/src/AgentList.cpp | 10 +++++++-- 4 files changed, 35 insertions(+), 22 deletions(-) diff --git a/domain/src/main.cpp b/domain/src/main.cpp index 4784a72ac0..faa15bd095 100644 --- a/domain/src/main.cpp +++ b/domain/src/main.cpp @@ -28,6 +28,7 @@ #include #include #include "AgentList.h" +#include "SharedUtil.h" const int DOMAIN_LISTEN_PORT = 40102; @@ -41,30 +42,19 @@ const int LOGOFF_CHECK_INTERVAL = 5000; int lastActiveCount = 0; AgentList agentList(DOMAIN_LISTEN_PORT); -int listForBroadcast(unsigned char *listBuffer, sockaddr *agentPublicAddress, sockaddr *agentLocalAddress, char agentType) { - unsigned char *currentBufferPos = listBuffer + 1; - unsigned char *startPointer = currentBufferPos; - - for(std::vector::iterator agent = agentList.agents.begin(); agent != agentList.agents.end(); agent++) { - - if (DEBUG_TO_SELF || !agent->matches(agentPublicAddress, agentLocalAddress, agentType)) { - *currentBufferPos++ = agent->type; - - currentBufferPos += packSocket(currentBufferPos, agent->publicSocket); - currentBufferPos += packSocket(currentBufferPos, agent->localSocket); - } - } - - return 1 + (currentBufferPos - startPointer); // 1 is added for the leading 'D' -} int main(int argc, const char * argv[]) { ssize_t receivedBytes = 0; char agentType; + unsigned char *broadcastPacket = new unsigned char[MAX_PACKET_SIZE]; *broadcastPacket = 'D'; + unsigned char *currentBufferPos; + unsigned char *startPointer; + int packetBytesWithoutLeadingChar; + sockaddr_in agentPublicAddress, agentLocalAddress; agentLocalAddress.sin_family = AF_INET; @@ -77,10 +67,26 @@ int main(int argc, const char * argv[]) agentList.addOrUpdateAgent((sockaddr *)&agentPublicAddress, (sockaddr *)&agentLocalAddress, agentType); - int listBytes = listForBroadcast(broadcastPacket, (sockaddr *)&agentPublicAddress, (sockaddr *)&agentLocalAddress, agentType); + currentBufferPos = broadcastPacket + 1; + startPointer = currentBufferPos; - if (listBytes > 0) { - agentList.getAgentSocket()->send((sockaddr *)&agentPublicAddress, broadcastPacket, listBytes); + for(std::vector::iterator agent = agentList.agents.begin(); agent != agentList.agents.end(); agent++) { + + if (DEBUG_TO_SELF || !agent->matches((sockaddr *)&agentPublicAddress, (sockaddr *)&agentLocalAddress, agentType)) { + *currentBufferPos++ = agent->type; + + currentBufferPos += packSocket(currentBufferPos, agent->publicSocket); + currentBufferPos += packSocket(currentBufferPos, agent->localSocket); + } else { + // this is the agent, just update last receive to now + agent->lastRecvTimeUsecs = usecTimestampNow(); + } + } + + ; + + if ((packetBytesWithoutLeadingChar = (currentBufferPos - startPointer))) { + agentList.getAgentSocket()->send((sockaddr *)&agentPublicAddress, broadcastPacket, packetBytesWithoutLeadingChar); } } } diff --git a/interface/src/main.cpp b/interface/src/main.cpp index 7ff9b91301..9d7b4a2853 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -55,7 +55,7 @@ int simulate_on = 1; const int MAX_PACKET_SIZE = 1500; char DOMAIN_HOSTNAME[] = "highfidelity.below92.com"; -char DOMAIN_IP[100] = ""; // IP Address will be used first if not empty string +char DOMAIN_IP[100] = "192.168.1.47"; // IP Address will be used first if not empty string const int DOMAINSERVER_PORT = 40102; AgentList agentList; diff --git a/shared/src/Agent.cpp b/shared/src/Agent.cpp index a8a6984a09..5b48033225 100644 --- a/shared/src/Agent.cpp +++ b/shared/src/Agent.cpp @@ -43,6 +43,7 @@ Agent::Agent(const Agent &otherAgent) { activeSocket = NULL; } + lastRecvTimeUsecs = otherAgent.lastRecvTimeUsecs; type = otherAgent.type; // linked data is transient, gets re-assigned on next packet receive diff --git a/shared/src/AgentList.cpp b/shared/src/AgentList.cpp index d743353820..d068ab15fc 100644 --- a/shared/src/AgentList.cpp +++ b/shared/src/AgentList.cpp @@ -153,8 +153,14 @@ bool AgentList::addOrUpdateAgent(sockaddr *publicSocket, sockaddr *localSocket, return true; } else { - // we had this agent already, just update receive timestamp - agent->lastRecvTimeUsecs = usecTimestampNow(); + + if (agent->type == 'M') { + // 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->lastRecvTimeUsecs = usecTimestampNow(); + } + + // we had this agent already, do nothing for now return false; } }