mirror of
https://github.com/lubosz/overte.git
synced 2025-04-26 15:15:27 +02:00
Merge pull request #1031 from birarda/avatar-mixer-dopplegangers
fix for avatar-mixer agent drops and double adds
This commit is contained in:
commit
939a145d90
8 changed files with 14 additions and 245 deletions
|
@ -15,7 +15,6 @@ set(CMAKE_AUTOMOC ON)
|
|||
add_subdirectory(animation-server)
|
||||
add_subdirectory(assignment-client)
|
||||
add_subdirectory(domain-server)
|
||||
add_subdirectory(eve)
|
||||
add_subdirectory(interface)
|
||||
add_subdirectory(injector)
|
||||
add_subdirectory(pairing-server)
|
||||
|
|
|
@ -98,7 +98,7 @@ void AvatarMixer::run() {
|
|||
|
||||
nodeList->startSilentNodeRemovalThread();
|
||||
|
||||
sockaddr* nodeAddress = new sockaddr;
|
||||
sockaddr nodeAddress = {};
|
||||
ssize_t receivedBytes = 0;
|
||||
|
||||
unsigned char* packetData = new unsigned char[MAX_PACKET_SIZE];
|
||||
|
@ -107,8 +107,6 @@ void AvatarMixer::run() {
|
|||
Node* avatarNode = NULL;
|
||||
|
||||
timeval lastDomainServerCheckIn = {};
|
||||
// we only need to hear back about avatar nodes from the DS
|
||||
nodeList->setNodeTypesOfInterest(&NODE_TYPE_AGENT, 1);
|
||||
|
||||
while (true) {
|
||||
|
||||
|
@ -122,7 +120,7 @@ void AvatarMixer::run() {
|
|||
NodeList::getInstance()->sendDomainServerCheckIn(_uuid.toRfc4122().constData());
|
||||
}
|
||||
|
||||
if (nodeList->getNodeSocket()->receive(nodeAddress, packetData, &receivedBytes) &&
|
||||
if (nodeList->getNodeSocket()->receive(&nodeAddress, packetData, &receivedBytes) &&
|
||||
packetVersionMatch(packetData)) {
|
||||
switch (packetData[0]) {
|
||||
case PACKET_TYPE_HEAD_DATA:
|
||||
|
@ -130,12 +128,12 @@ void AvatarMixer::run() {
|
|||
unpackNodeId(packetData + numBytesForPacketHeader(packetData), &nodeID);
|
||||
|
||||
// add or update the node in our list
|
||||
avatarNode = nodeList->addOrUpdateNode(nodeAddress, nodeAddress, NODE_TYPE_AGENT, nodeID);
|
||||
avatarNode = nodeList->addOrUpdateNode(&nodeAddress, &nodeAddress, NODE_TYPE_AGENT, nodeID);
|
||||
|
||||
// parse positional data from an node
|
||||
nodeList->updateNodeWithData(avatarNode, packetData, receivedBytes);
|
||||
case PACKET_TYPE_INJECT_AUDIO:
|
||||
broadcastAvatarData(nodeList, nodeAddress);
|
||||
broadcastAvatarData(nodeList, &nodeAddress);
|
||||
break;
|
||||
case PACKET_TYPE_AVATAR_URLS:
|
||||
case PACKET_TYPE_AVATAR_FACE_VIDEO:
|
||||
|
@ -151,7 +149,7 @@ void AvatarMixer::run() {
|
|||
break;
|
||||
default:
|
||||
// hand this off to the NodeList
|
||||
nodeList->processNodeData(nodeAddress, packetData, receivedBytes);
|
||||
nodeList->processNodeData(&nodeAddress, packetData, receivedBytes);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,21 +0,0 @@
|
|||
cmake_minimum_required(VERSION 2.8)
|
||||
|
||||
set(ROOT_DIR ..)
|
||||
set(MACRO_DIR ${ROOT_DIR}/cmake/macros)
|
||||
|
||||
# setup for find modules
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../cmake/modules/")
|
||||
|
||||
set(TARGET_NAME eve)
|
||||
|
||||
include(${MACRO_DIR}/SetupHifiProject.cmake)
|
||||
setup_hifi_project(${TARGET_NAME} TRUE)
|
||||
|
||||
include(${MACRO_DIR}/IncludeGLM.cmake)
|
||||
include_glm(${TARGET_NAME} ${ROOT_DIR})
|
||||
|
||||
# link the required hifi libraries
|
||||
include(${MACRO_DIR}/LinkHifiLibrary.cmake)
|
||||
link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR})
|
||||
link_hifi_library(avatars ${TARGET_NAME} ${ROOT_DIR})
|
||||
link_hifi_library(audio ${TARGET_NAME} ${ROOT_DIR})
|
Binary file not shown.
212
eve/src/main.cpp
212
eve/src/main.cpp
|
@ -1,212 +0,0 @@
|
|||
//
|
||||
// main.cpp
|
||||
// eve
|
||||
//
|
||||
// Created by Stephen Birarda on 4/22/13.
|
||||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#include <cstring>
|
||||
#include <sys/time.h>
|
||||
#include <cstring>
|
||||
|
||||
#include <SharedUtil.h>
|
||||
#include <NodeTypes.h>
|
||||
#include <PacketHeaders.h>
|
||||
#include <NodeList.h>
|
||||
#include <AvatarData.h>
|
||||
#include <AudioInjectionManager.h>
|
||||
#include <AudioInjector.h>
|
||||
|
||||
const int EVE_NODE_LISTEN_PORT = 55441;
|
||||
|
||||
const float RANDOM_POSITION_MAX_DIMENSION = 10.0f;
|
||||
|
||||
const float DATA_SEND_INTERVAL_MSECS = 15;
|
||||
const float MIN_AUDIO_SEND_INTERVAL_SECS = 10;
|
||||
const int MIN_ITERATIONS_BETWEEN_AUDIO_SENDS = (MIN_AUDIO_SEND_INTERVAL_SECS * 1000) / DATA_SEND_INTERVAL_MSECS;
|
||||
const int MAX_AUDIO_SEND_INTERVAL_SECS = 15;
|
||||
const float MAX_ITERATIONS_BETWEEN_AUDIO_SENDS = (MAX_AUDIO_SEND_INTERVAL_SECS * 1000) / DATA_SEND_INTERVAL_MSECS;
|
||||
|
||||
const int ITERATIONS_BEFORE_HAND_GRAB = 100;
|
||||
const int HAND_GRAB_DURATION_ITERATIONS = 50;
|
||||
const int HAND_TIMER_SLEEP_ITERATIONS = 50;
|
||||
|
||||
const float EVE_PELVIS_HEIGHT = 0.565925f;
|
||||
|
||||
const float AUDIO_INJECT_PROXIMITY = 0.4f;
|
||||
const int EVE_VOLUME_BYTE = 190;
|
||||
|
||||
const char EVE_AUDIO_FILENAME[] = "/etc/highfidelity/eve/resources/eve.raw";
|
||||
|
||||
bool stopReceiveNodeDataThread;
|
||||
|
||||
void *receiveNodeData(void *args) {
|
||||
sockaddr senderAddress;
|
||||
ssize_t bytesReceived;
|
||||
unsigned char incomingPacket[MAX_PACKET_SIZE];
|
||||
|
||||
NodeList* nodeList = NodeList::getInstance();
|
||||
|
||||
while (!::stopReceiveNodeDataThread) {
|
||||
if (nodeList->getNodeSocket()->receive(&senderAddress, incomingPacket, &bytesReceived) &&
|
||||
packetVersionMatch(incomingPacket)) {
|
||||
switch (incomingPacket[0]) {
|
||||
case PACKET_TYPE_BULK_AVATAR_DATA:
|
||||
// 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 nodeList handle list of nodes from DS, replies from other nodes, etc.
|
||||
nodeList->processNodeData(&senderAddress, incomingPacket, bytesReceived);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pthread_exit(0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void createAvatarDataForNode(Node* node) {
|
||||
if (!node->getLinkedData()) {
|
||||
node->setLinkedData(new AvatarData(node));
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, const char* argv[]) {
|
||||
// new seed for random audio sleep times
|
||||
srand(time(0));
|
||||
|
||||
// create an NodeList instance to handle communication with other nodes
|
||||
NodeList* nodeList = NodeList::createInstance(NODE_TYPE_AGENT, EVE_NODE_LISTEN_PORT);
|
||||
|
||||
// start the node list thread that will kill off nodes when they stop talking
|
||||
nodeList->startSilentNodeRemovalThread();
|
||||
|
||||
pthread_t receiveNodeDataThread;
|
||||
pthread_create(&receiveNodeDataThread, NULL, receiveNodeData, NULL);
|
||||
|
||||
// create an AvatarData object, "eve"
|
||||
AvatarData eve;
|
||||
|
||||
// move eve away from the origin
|
||||
// pick a random point inside a 10x10 grid
|
||||
|
||||
eve.setPosition(glm::vec3(randFloatInRange(0, RANDOM_POSITION_MAX_DIMENSION),
|
||||
EVE_PELVIS_HEIGHT, // this should be the same as the avatar's pelvis standing height
|
||||
randFloatInRange(0, RANDOM_POSITION_MAX_DIMENSION)));
|
||||
|
||||
// face any instance of eve down the z-axis
|
||||
eve.setBodyYaw(0);
|
||||
|
||||
// put her hand out so somebody can shake it
|
||||
eve.setHandPosition(glm::vec3(eve.getPosition()[0] - 0.2,
|
||||
0.5,
|
||||
eve.getPosition()[2] + 0.1));
|
||||
|
||||
// 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);
|
||||
|
||||
// lower Eve's volume by setting the attentuation modifier (this is a value out of 255)
|
||||
eveAudioInjector.setVolume(EVE_VOLUME_BYTE);
|
||||
|
||||
// set the position of the audio injector
|
||||
eveAudioInjector.setPosition(eve.getPosition());
|
||||
|
||||
// register the callback for node data creation
|
||||
nodeList->linkedDataCreateCallback = createAvatarDataForNode;
|
||||
|
||||
unsigned char broadcastPacket[MAX_PACKET_SIZE];
|
||||
int numHeaderBytes = populateTypeAndVersion(broadcastPacket, PACKET_TYPE_HEAD_DATA);
|
||||
|
||||
timeval thisSend;
|
||||
int numMicrosecondsSleep = 0;
|
||||
|
||||
int handStateTimer = 0;
|
||||
|
||||
timeval lastDomainServerCheckIn = {};
|
||||
|
||||
// eve wants to hear about an avatar mixer and an audio mixer from the domain server
|
||||
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);
|
||||
NodeList::getInstance()->sendDomainServerCheckIn();
|
||||
}
|
||||
|
||||
// update the thisSend timeval to the current time
|
||||
gettimeofday(&thisSend, NULL);
|
||||
|
||||
// find the current avatar mixer
|
||||
Node* avatarMixer = nodeList->soloNodeOfType(NODE_TYPE_AVATAR_MIXER);
|
||||
|
||||
// make sure we actually have an avatar mixer with an active socket
|
||||
if (nodeList->getOwnerID() != UNKNOWN_NODE_ID && avatarMixer && avatarMixer->getActiveSocket() != NULL) {
|
||||
unsigned char* packetPosition = broadcastPacket + numHeaderBytes;
|
||||
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 node list to send avatar data to mixer
|
||||
nodeList->getNodeSocket()->send(avatarMixer->getActiveSocket(), broadcastPacket, packetPosition - broadcastPacket);
|
||||
}
|
||||
|
||||
if (!eveAudioInjector.isInjectingAudio()) {
|
||||
// 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 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
|
||||
AudioInjectionManager::setDestinationSocket(*audioMixer->getPublicSocket());
|
||||
|
||||
// we have an active audio mixer we can send data to
|
||||
AudioInjectionManager::threadInjector(&eveAudioInjector);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// simulate the effect of pressing and un-pressing the mouse button/pad
|
||||
handStateTimer++;
|
||||
|
||||
if (handStateTimer == ITERATIONS_BEFORE_HAND_GRAB) {
|
||||
eve.setHandState(1);
|
||||
} else if (handStateTimer == ITERATIONS_BEFORE_HAND_GRAB + HAND_GRAB_DURATION_ITERATIONS) {
|
||||
eve.setHandState(0);
|
||||
} else if (handStateTimer >= ITERATIONS_BEFORE_HAND_GRAB + HAND_GRAB_DURATION_ITERATIONS + HAND_TIMER_SLEEP_ITERATIONS) {
|
||||
handStateTimer = 0;
|
||||
}
|
||||
|
||||
// sleep for the correct amount of time to have data send be consistently timed
|
||||
if ((numMicrosecondsSleep = (DATA_SEND_INTERVAL_MSECS * 1000) - (usecTimestampNow() - usecTimestamp(&thisSend))) > 0) {
|
||||
usleep(numMicrosecondsSleep);
|
||||
}
|
||||
}
|
||||
|
||||
// stop the receive node data thread
|
||||
stopReceiveNodeDataThread = true;
|
||||
pthread_join(receiveNodeDataThread, NULL);
|
||||
|
||||
// stop the node list's threads
|
||||
nodeList->stopSilentNodeRemovalThread();
|
||||
}
|
|
@ -428,6 +428,7 @@ void NodeList::sendAssignment(Assignment& assignment) {
|
|||
}
|
||||
|
||||
Node* NodeList::addOrUpdateNode(sockaddr* publicSocket, sockaddr* localSocket, char nodeType, uint16_t nodeId) {
|
||||
|
||||
NodeList::iterator node = end();
|
||||
|
||||
if (publicSocket) {
|
||||
|
@ -439,7 +440,7 @@ Node* NodeList::addOrUpdateNode(sockaddr* publicSocket, sockaddr* localSocket, c
|
|||
}
|
||||
}
|
||||
|
||||
if (node == end()) {
|
||||
if (node == end()) {
|
||||
// we didn't have this node, so add them
|
||||
Node* newNode = new Node(publicSocket, localSocket, nodeType, nodeId);
|
||||
|
||||
|
@ -540,6 +541,8 @@ void* removeSilentNodes(void *args) {
|
|||
|
||||
for(NodeList::iterator node = nodeList->begin(); node != nodeList->end(); ++node) {
|
||||
|
||||
node->lock();
|
||||
|
||||
if ((checkTimeUSecs - node->getLastHeardMicrostamp()) > NODE_SILENCE_THRESHOLD_USECS) {
|
||||
|
||||
qDebug() << "Killed " << *node << "\n";
|
||||
|
@ -548,6 +551,8 @@ void* removeSilentNodes(void *args) {
|
|||
|
||||
node->setAlive(false);
|
||||
}
|
||||
|
||||
node->unlock();
|
||||
}
|
||||
|
||||
sleepTime = NODE_SILENCE_THRESHOLD_USECS - (usecTimestampNow() - checkTimeUSecs);
|
||||
|
|
|
@ -30,7 +30,7 @@ const int NODES_PER_BUCKET = 100;
|
|||
|
||||
const int MAX_PACKET_SIZE = 1500;
|
||||
|
||||
const int NODE_SILENCE_THRESHOLD_USECS = 2 * 1000000;
|
||||
const uint64_t NODE_SILENCE_THRESHOLD_USECS = 2 * 1000000;
|
||||
const int DOMAIN_SERVER_CHECK_IN_USECS = 1 * 1000000;
|
||||
|
||||
extern const char SOLO_NODE_TYPES[2];
|
||||
|
|
|
@ -43,7 +43,7 @@ bool socketMatch(const sockaddr* first, const sockaddr* second) {
|
|||
const sockaddr_in *secondIn = (const sockaddr_in *) second;
|
||||
|
||||
return firstIn->sin_addr.s_addr == secondIn->sin_addr.s_addr
|
||||
&& firstIn->sin_port == secondIn->sin_port;
|
||||
&& firstIn->sin_port == secondIn->sin_port;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
@ -254,7 +254,7 @@ bool UDPSocket::receive(sockaddr* recvAddress, void* receivedData, ssize_t* rece
|
|||
#ifdef _WIN32
|
||||
int addressSize = sizeof(*recvAddress);
|
||||
#else
|
||||
socklen_t addressSize = sizeof(&recvAddress);
|
||||
socklen_t addressSize = sizeof(*recvAddress);
|
||||
#endif
|
||||
*receivedBytes = recvfrom(handle, static_cast<char*>(receivedData), MAX_BUFFER_LENGTH_BYTES,
|
||||
0, recvAddress, &addressSize);
|
||||
|
|
Loading…
Reference in a new issue