From 7e1a823a258e0bf4e683a2915a77b82ccfb99882 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 25 Nov 2013 16:39:01 -0600 Subject: [PATCH 01/31] add AssignmentClient to be correct subclass of QCoreApplication --- assignment-client/src/AssignmentClient.cpp | 112 +++++++++++++++++++++ assignment-client/src/AssignmentClient.h | 29 ++++++ assignment-client/src/main.cpp | 86 +--------------- 3 files changed, 146 insertions(+), 81 deletions(-) create mode 100644 assignment-client/src/AssignmentClient.cpp create mode 100644 assignment-client/src/AssignmentClient.h diff --git a/assignment-client/src/AssignmentClient.cpp b/assignment-client/src/AssignmentClient.cpp new file mode 100644 index 0000000000..ec7ae6fc92 --- /dev/null +++ b/assignment-client/src/AssignmentClient.cpp @@ -0,0 +1,112 @@ +// +// AssignmentClient.cpp +// hifi +// +// Created by Stephen Birarda on 11/25/2013. +// Copyright (c) 2013 HighFidelity, Inc. All rights reserved. +// + +#include +#include +#include +#include +#include + +#include "AssignmentFactory.h" + +#include "AssignmentClient.h" + +const char ASSIGNMENT_CLIENT_TARGET_NAME[] = "assignment-client"; +const long long ASSIGNMENT_REQUEST_INTERVAL_USECS = 1 * 1000 * 1000; + +AssignmentClient::AssignmentClient(int &argc, char **argv, + Assignment::Type requestAssignmentType, + const sockaddr_in& customAssignmentServerSocket, + const char* requestAssignmentPool) : + QCoreApplication(argc, argv), + _requestAssignmentType(requestAssignmentType), + _customAssignmentServerSocket(customAssignmentServerSocket), + _requestAssignmentPool(requestAssignmentPool) +{ + +} + +int AssignmentClient::exec() { + // set the logging target to the the CHILD_TARGET_NAME + Logging::setTargetName(ASSIGNMENT_CLIENT_TARGET_NAME); + + // create a NodeList as an unassigned client + NodeList* nodeList = NodeList::createInstance(NODE_TYPE_UNASSIGNED); + + // set the custom assignment socket if we have it + if (_customAssignmentServerSocket.sin_addr.s_addr != 0) { + nodeList->setAssignmentServerSocket((sockaddr*) &_customAssignmentServerSocket); + } + + // change the timeout on the nodelist socket to be as often as we want to re-request + nodeList->getNodeSocket()->setBlockingReceiveTimeoutInUsecs(ASSIGNMENT_REQUEST_INTERVAL_USECS); + + timeval lastRequest = {}; + + unsigned char packetData[MAX_PACKET_SIZE]; + ssize_t receivedBytes = 0; + + sockaddr_in senderSocket = {}; + + // create a request assignment, accept assignments defined by the overidden type + Assignment requestAssignment(Assignment::RequestCommand, _requestAssignmentType, _requestAssignmentPool); + + qDebug() << "Waiting for assignment -" << requestAssignment << "\n"; + + while (true) { + if (usecTimestampNow() - usecTimestamp(&lastRequest) >= ASSIGNMENT_REQUEST_INTERVAL_USECS) { + gettimeofday(&lastRequest, NULL); + + // if we're here we have no assignment, so send a request + nodeList->sendAssignment(requestAssignment); + } + + if (nodeList->getNodeSocket()->receive((sockaddr*) &senderSocket, packetData, &receivedBytes) && + (packetData[0] == PACKET_TYPE_DEPLOY_ASSIGNMENT || packetData[0] == PACKET_TYPE_CREATE_ASSIGNMENT) + && packetVersionMatch(packetData)) { + + // construct the deployed assignment from the packet data + Assignment* deployedAssignment = AssignmentFactory::unpackAssignment(packetData, receivedBytes); + + qDebug() << "Received an assignment -" << *deployedAssignment << "\n"; + + // switch our nodelist domain IP and port to whoever sent us the assignment + if (packetData[0] == PACKET_TYPE_CREATE_ASSIGNMENT) { + + nodeList->setDomainIP(QHostAddress((sockaddr*) &senderSocket)); + nodeList->setDomainPort(ntohs(senderSocket.sin_port)); + + nodeList->setOwnerUUID(deployedAssignment->getUUID()); + + qDebug("Destination IP for assignment is %s\n", nodeList->getDomainIP().toString().toStdString().c_str()); + + // run the deployed assignment + deployedAssignment->run(); + } else { + qDebug("Received a bad destination socket for assignment.\n"); + } + + qDebug("Assignment finished or never started - waiting for new assignment\n"); + + // delete the deployedAssignment + delete deployedAssignment; + + // reset our NodeList by switching back to unassigned and clearing the list + nodeList->setOwnerType(NODE_TYPE_UNASSIGNED); + nodeList->reset(); + + // set the NodeList socket back to blocking + nodeList->getNodeSocket()->setBlocking(true); + + // reset the logging target to the the CHILD_TARGET_NAME + Logging::setTargetName(ASSIGNMENT_CLIENT_TARGET_NAME); + } + } + + return 0; +} diff --git a/assignment-client/src/AssignmentClient.h b/assignment-client/src/AssignmentClient.h new file mode 100644 index 0000000000..26f1f952c0 --- /dev/null +++ b/assignment-client/src/AssignmentClient.h @@ -0,0 +1,29 @@ +// +// AssignmentClient.h +// hifi +// +// Created by Stephen Birarda on 11/25/2013. +// Copyright (c) 2013 HighFidelity, Inc. All rights reserved. +// + +#ifndef __hifi__AssignmentClient__ +#define __hifi__AssignmentClient__ + +#include + +class AssignmentClient : public QCoreApplication { + Q_OBJECT +public: + AssignmentClient(int &argc, char **argv, + Assignment::Type requestAssignmentType = Assignment::AllTypes, + const sockaddr_in& customAssignmentServerSocket = sockaddr_in(), + const char* requestAssignmentPool = NULL); + + int exec(); +private: + Assignment::Type _requestAssignmentType; + sockaddr_in _customAssignmentServerSocket; + const char* _requestAssignmentPool; +}; + +#endif /* defined(__hifi__AssignmentClient__) */ diff --git a/assignment-client/src/main.cpp b/assignment-client/src/main.cpp index 6f8cd83784..5f98f4f856 100644 --- a/assignment-client/src/main.cpp +++ b/assignment-client/src/main.cpp @@ -20,13 +20,12 @@ #include "Agent.h" #include "Assignment.h" +#include "AssignmentClient.h" #include "AssignmentFactory.h" #include "audio/AudioMixer.h" #include "avatars/AvatarMixer.h" -const long long ASSIGNMENT_REQUEST_INTERVAL_USECS = 1 * 1000 * 1000; const char PARENT_TARGET_NAME[] = "assignment-client-monitor"; -const char CHILD_TARGET_NAME[] = "assignment-client"; pid_t* childForks = NULL; sockaddr_in customAssignmentSocket = {}; @@ -37,84 +36,9 @@ const char* assignmentPool = NULL; int argc = 0; char** argv = NULL; -void childClient() { - QCoreApplication application(::argc, ::argv); - - // set the logging target to the the CHILD_TARGET_NAME - Logging::setTargetName(CHILD_TARGET_NAME); - - // create a NodeList as an unassigned client - NodeList* nodeList = NodeList::createInstance(NODE_TYPE_UNASSIGNED); - - // set the custom assignment socket if we have it - if (customAssignmentSocket.sin_addr.s_addr != 0) { - nodeList->setAssignmentServerSocket((sockaddr*) &customAssignmentSocket); - } - - // change the timeout on the nodelist socket to be as often as we want to re-request - nodeList->getNodeSocket()->setBlockingReceiveTimeoutInUsecs(ASSIGNMENT_REQUEST_INTERVAL_USECS); - - timeval lastRequest = {}; - - unsigned char packetData[MAX_PACKET_SIZE]; - ssize_t receivedBytes = 0; - - sockaddr_in senderSocket = {}; - - // create a request assignment, accept assignments defined by the overidden type - Assignment requestAssignment(Assignment::RequestCommand, ::overiddenAssignmentType, ::assignmentPool); - - qDebug() << "Waiting for assignment -" << requestAssignment << "\n"; - - while (true) { - if (usecTimestampNow() - usecTimestamp(&lastRequest) >= ASSIGNMENT_REQUEST_INTERVAL_USECS) { - gettimeofday(&lastRequest, NULL); - - // if we're here we have no assignment, so send a request - nodeList->sendAssignment(requestAssignment); - } - - if (nodeList->getNodeSocket()->receive((sockaddr*) &senderSocket, packetData, &receivedBytes) && - (packetData[0] == PACKET_TYPE_DEPLOY_ASSIGNMENT || packetData[0] == PACKET_TYPE_CREATE_ASSIGNMENT) - && packetVersionMatch(packetData)) { - - // construct the deployed assignment from the packet data - Assignment* deployedAssignment = AssignmentFactory::unpackAssignment(packetData, receivedBytes); - - qDebug() << "Received an assignment -" << *deployedAssignment << "\n"; - - // switch our nodelist domain IP and port to whoever sent us the assignment - if (packetData[0] == PACKET_TYPE_CREATE_ASSIGNMENT) { - - nodeList->setDomainIP(QHostAddress((sockaddr*) &senderSocket)); - nodeList->setDomainPort(ntohs(senderSocket.sin_port)); - - nodeList->setOwnerUUID(deployedAssignment->getUUID()); - - qDebug("Destination IP for assignment is %s\n", nodeList->getDomainIP().toString().toStdString().c_str()); - - // run the deployed assignment - deployedAssignment->run(); - } else { - qDebug("Received a bad destination socket for assignment.\n"); - } - - qDebug("Assignment finished or never started - waiting for new assignment\n"); - - // delete the deployedAssignment - delete deployedAssignment; - - // reset our NodeList by switching back to unassigned and clearing the list - nodeList->setOwnerType(NODE_TYPE_UNASSIGNED); - nodeList->reset(); - - // set the NodeList socket back to blocking - nodeList->getNodeSocket()->setBlocking(true); - - // reset the logging target to the the CHILD_TARGET_NAME - Logging::setTargetName(CHILD_TARGET_NAME); - } - } +int childClient() { + AssignmentClient client(::argc, ::argv, ::overiddenAssignmentType, customAssignmentSocket, ::assignmentPool); + return client.exec(); } void sigchldHandler(int sig) { @@ -247,7 +171,7 @@ int main(int argc, char* argv[]) { } if (processID == 0 || ::numForks == 0) { - childClient(); + return childClient(); } else { parentMonitor(); } From 1e3ab1a20131c760c69f604b253e471ac5d22e29 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 26 Nov 2013 10:36:34 -0600 Subject: [PATCH 02/31] remove cURL from Agent code --- assignment-client/src/Agent.cpp | 231 +++++++++++++------------------- 1 file changed, 96 insertions(+), 135 deletions(-) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index 4319ca706e..2492138857 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -6,7 +6,10 @@ // Copyright (c) 2013 HighFidelity, Inc. All rights reserved. // -#include +#include +#include +#include +#include #include #include @@ -27,18 +30,6 @@ void Agent::stop() { _shouldStop = true; } -static size_t writeScriptDataToString(void *contents, size_t size, size_t nmemb, void *userdata) { - size_t realSize = size * nmemb; - - QString* scriptContents = (QString*) userdata; - - // append this chunk to the scriptContents - scriptContents->append(QByteArray((char*) contents, realSize)); - - // return the amount of data read - return realSize; -} - QScriptValue vec3toScriptValue(QScriptEngine *engine, const glm::vec3 &vec3) { QScriptValue obj = engine->newObject(); obj.setProperty("x", vec3.x); @@ -68,141 +59,111 @@ void Agent::run() { scriptURLString = scriptURLString.arg(NodeList::getInstance()->getDomainIP().toString(), uuidStringWithoutCurlyBraces(_uuid)); - // setup curl for script download - CURLcode curlResult; - - CURL* curlHandle = curl_easy_init(); - - // tell curl which file to grab - curl_easy_setopt(curlHandle, CURLOPT_URL, scriptURLString.toStdString().c_str()); - - // send the data to the WriteMemoryCallback function - curl_easy_setopt(curlHandle, CURLOPT_WRITEFUNCTION, writeScriptDataToString); - - QString scriptContents; - - // pass the scriptContents QString to append data to - curl_easy_setopt(curlHandle, CURLOPT_WRITEDATA, (void *)&scriptContents); - - // send a user agent since some servers will require it - curl_easy_setopt(curlHandle, CURLOPT_USERAGENT, "libcurl-agent/1.0"); - - // make sure CURL fails on a 400 code - curl_easy_setopt(curlHandle, CURLOPT_FAILONERROR, true); + QNetworkAccessManager *networkManager = new QNetworkAccessManager(this); + QNetworkReply *reply = networkManager->get(QNetworkRequest(QUrl(scriptURLString))); qDebug() << "Downloading script at" << scriptURLString << "\n"; - // blocking get for JS file - curlResult = curl_easy_perform(curlHandle); - - if (curlResult == CURLE_OK) { - // cleanup curl - curl_easy_cleanup(curlHandle); - curl_global_cleanup(); + QEventLoop loop; + QObject::connect(reply, SIGNAL(finished()), &loop, SLOT(quit())); + + loop.exec(); + + QString scriptContents(reply->readAll()); + QScriptEngine engine; + + // register meta-type for glm::vec3 conversions + qScriptRegisterMetaType(&engine, vec3toScriptValue, vec3FromScriptValue); + + QScriptValue agentValue = engine.newQObject(this); + engine.globalObject().setProperty("Agent", agentValue); + + VoxelScriptingInterface voxelScripter; + QScriptValue voxelScripterValue = engine.newQObject(&voxelScripter); + engine.globalObject().setProperty("Voxels", voxelScripterValue); + + QScriptValue treeScaleValue = engine.newVariant(QVariant(TREE_SCALE)); + engine.globalObject().setProperty("TREE_SCALE", treeScaleValue); + + const unsigned int VISUAL_DATA_CALLBACK_USECS = (1.0 / 60.0) * 1000 * 1000; + + // let the VoxelPacketSender know how frequently we plan to call it + voxelScripter.getVoxelPacketSender()->setProcessCallIntervalHint(VISUAL_DATA_CALLBACK_USECS); + + // hook in a constructor for audio injectorss + AudioInjector scriptedAudioInjector(BUFFER_LENGTH_SAMPLES_PER_CHANNEL); + QScriptValue audioInjectorValue = engine.newQObject(&scriptedAudioInjector); + engine.globalObject().setProperty("AudioInjector", audioInjectorValue); + + qDebug() << "Downloaded script:" << scriptContents << "\n"; + QScriptValue result = engine.evaluate(scriptContents); + qDebug() << "Evaluated script.\n"; + + if (engine.hasUncaughtException()) { + int line = engine.uncaughtExceptionLineNumber(); + qDebug() << "Uncaught exception at line" << line << ":" << result.toString() << "\n"; + } + + timeval startTime; + gettimeofday(&startTime, NULL); + + timeval lastDomainServerCheckIn = {}; + + sockaddr_in senderAddress; + unsigned char receivedData[MAX_PACKET_SIZE]; + ssize_t receivedBytes; + + int thisFrame = 0; + + NodeList::getInstance()->startSilentNodeRemovalThread(); + + while (!_shouldStop) { - QScriptEngine engine; + // if we're not hearing from the domain-server we should stop running + if (NodeList::getInstance()->getNumNoReplyDomainCheckIns() == MAX_SILENT_DOMAIN_SERVER_CHECK_INS) { + break; + } - // register meta-type for glm::vec3 conversions - qScriptRegisterMetaType(&engine, vec3toScriptValue, vec3FromScriptValue); + // 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(); + } - QScriptValue agentValue = engine.newQObject(this); - engine.globalObject().setProperty("Agent", agentValue); + int usecToSleep = usecTimestamp(&startTime) + (thisFrame++ * VISUAL_DATA_CALLBACK_USECS) - usecTimestampNow(); + if (usecToSleep > 0) { + usleep(usecToSleep); + } - VoxelScriptingInterface voxelScripter; - QScriptValue voxelScripterValue = engine.newQObject(&voxelScripter); - engine.globalObject().setProperty("Voxels", voxelScripterValue); - - QScriptValue treeScaleValue = engine.newVariant(QVariant(TREE_SCALE)); - engine.globalObject().setProperty("TREE_SCALE", treeScaleValue); - - const unsigned int VISUAL_DATA_CALLBACK_USECS = (1.0 / 60.0) * 1000 * 1000; - - // let the VoxelPacketSender know how frequently we plan to call it - voxelScripter.getVoxelPacketSender()->setProcessCallIntervalHint(VISUAL_DATA_CALLBACK_USECS); - - // hook in a constructor for audio injectorss - AudioInjector scriptedAudioInjector(BUFFER_LENGTH_SAMPLES_PER_CHANNEL); - QScriptValue audioInjectorValue = engine.newQObject(&scriptedAudioInjector); - engine.globalObject().setProperty("AudioInjector", audioInjectorValue); - - qDebug() << "Downloaded script:" << scriptContents << "\n"; - QScriptValue result = engine.evaluate(scriptContents); - qDebug() << "Evaluated script.\n"; + if (voxelScripter.getVoxelPacketSender()->voxelServersExist()) { + timeval thisSend = {}; + gettimeofday(&thisSend, NULL); + // allow the scripter's call back to setup visual data + emit willSendVisualDataCallback(); + + // release the queue of edit voxel messages. + voxelScripter.getVoxelPacketSender()->releaseQueuedMessages(); + + // since we're in non-threaded mode, call process so that the packets are sent + voxelScripter.getVoxelPacketSender()->process(); + } if (engine.hasUncaughtException()) { int line = engine.uncaughtExceptionLineNumber(); - qDebug() << "Uncaught exception at line" << line << ":" << result.toString() << "\n"; + qDebug() << "Uncaught exception at line" << line << ":" << engine.uncaughtException().toString() << "\n"; } - timeval startTime; - gettimeofday(&startTime, NULL); - - timeval lastDomainServerCheckIn = {}; - - sockaddr_in senderAddress; - unsigned char receivedData[MAX_PACKET_SIZE]; - ssize_t receivedBytes; - - int thisFrame = 0; - - NodeList::getInstance()->startSilentNodeRemovalThread(); - - while (!_shouldStop) { - - // if we're not hearing from the domain-server we should stop running - if (NodeList::getInstance()->getNumNoReplyDomainCheckIns() == MAX_SILENT_DOMAIN_SERVER_CHECK_INS) { - break; - } - - // 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(); - } - - int usecToSleep = usecTimestamp(&startTime) + (thisFrame++ * VISUAL_DATA_CALLBACK_USECS) - usecTimestampNow(); - if (usecToSleep > 0) { - usleep(usecToSleep); - } - - if (voxelScripter.getVoxelPacketSender()->voxelServersExist()) { - timeval thisSend = {}; - gettimeofday(&thisSend, NULL); - // allow the scripter's call back to setup visual data - emit willSendVisualDataCallback(); - - // release the queue of edit voxel messages. - voxelScripter.getVoxelPacketSender()->releaseQueuedMessages(); - - // since we're in non-threaded mode, call process so that the packets are sent - voxelScripter.getVoxelPacketSender()->process(); - } - - if (engine.hasUncaughtException()) { - int line = engine.uncaughtExceptionLineNumber(); - qDebug() << "Uncaught exception at line" << line << ":" << engine.uncaughtException().toString() << "\n"; - } - - while (NodeList::getInstance()->getNodeSocket()->receive((sockaddr*) &senderAddress, receivedData, &receivedBytes) - && packetVersionMatch(receivedData)) { - if (receivedData[0] == PACKET_TYPE_VOXEL_JURISDICTION) { - voxelScripter.getJurisdictionListener()->queueReceivedPacket((sockaddr&) senderAddress, - receivedData, - receivedBytes); - } else { - NodeList::getInstance()->processNodeData((sockaddr*) &senderAddress, receivedData, receivedBytes); - } + while (NodeList::getInstance()->getNodeSocket()->receive((sockaddr*) &senderAddress, receivedData, &receivedBytes) + && packetVersionMatch(receivedData)) { + if (receivedData[0] == PACKET_TYPE_VOXEL_JURISDICTION) { + voxelScripter.getJurisdictionListener()->queueReceivedPacket((sockaddr&) senderAddress, + receivedData, + receivedBytes); + } else { + NodeList::getInstance()->processNodeData((sockaddr*) &senderAddress, receivedData, receivedBytes); } } - - NodeList::getInstance()->stopSilentNodeRemovalThread(); - - } else { - // error in curl_easy_perform - qDebug() << "curl_easy_perform for JS failed:" << curl_easy_strerror(curlResult) << "\n"; - - // cleanup curl - curl_easy_cleanup(curlHandle); - curl_global_cleanup(); } + + NodeList::getInstance()->stopSilentNodeRemovalThread(); } From d21583d9c51846d1bbfbc99482d04efa3a351fa1 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 26 Nov 2013 16:20:35 -0600 Subject: [PATCH 03/31] make AssignmentClient use event loop, closes #1291 --- assignment-client/src/AssignmentClient.cpp | 90 ++++------------------ assignment-client/src/AssignmentClient.h | 8 +- 2 files changed, 18 insertions(+), 80 deletions(-) diff --git a/assignment-client/src/AssignmentClient.cpp b/assignment-client/src/AssignmentClient.cpp index ec7ae6fc92..92d394f41a 100644 --- a/assignment-client/src/AssignmentClient.cpp +++ b/assignment-client/src/AssignmentClient.cpp @@ -6,6 +6,8 @@ // Copyright (c) 2013 HighFidelity, Inc. All rights reserved. // +#include + #include #include #include @@ -17,21 +19,15 @@ #include "AssignmentClient.h" const char ASSIGNMENT_CLIENT_TARGET_NAME[] = "assignment-client"; -const long long ASSIGNMENT_REQUEST_INTERVAL_USECS = 1 * 1000 * 1000; +const long long ASSIGNMENT_REQUEST_INTERVAL_MSECS = 1 * 1000; AssignmentClient::AssignmentClient(int &argc, char **argv, Assignment::Type requestAssignmentType, const sockaddr_in& customAssignmentServerSocket, const char* requestAssignmentPool) : QCoreApplication(argc, argv), - _requestAssignmentType(requestAssignmentType), - _customAssignmentServerSocket(customAssignmentServerSocket), - _requestAssignmentPool(requestAssignmentPool) + _requestAssignment(Assignment::RequestCommand, requestAssignmentType, requestAssignmentPool) { - -} - -int AssignmentClient::exec() { // set the logging target to the the CHILD_TARGET_NAME Logging::setTargetName(ASSIGNMENT_CLIENT_TARGET_NAME); @@ -39,74 +35,18 @@ int AssignmentClient::exec() { NodeList* nodeList = NodeList::createInstance(NODE_TYPE_UNASSIGNED); // set the custom assignment socket if we have it - if (_customAssignmentServerSocket.sin_addr.s_addr != 0) { - nodeList->setAssignmentServerSocket((sockaddr*) &_customAssignmentServerSocket); + if (customAssignmentServerSocket.sin_addr.s_addr != 0) { + nodeList->setAssignmentServerSocket((sockaddr*) &customAssignmentServerSocket); } - // change the timeout on the nodelist socket to be as often as we want to re-request - nodeList->getNodeSocket()->setBlockingReceiveTimeoutInUsecs(ASSIGNMENT_REQUEST_INTERVAL_USECS); + // call a timer function every ASSIGNMENT_REQUEST_INTERVAL_MSECS to ask for assignment, if required + qDebug() << "Waiting for assignment -" << _requestAssignment << "\n"; - timeval lastRequest = {}; - - unsigned char packetData[MAX_PACKET_SIZE]; - ssize_t receivedBytes = 0; - - sockaddr_in senderSocket = {}; - - // create a request assignment, accept assignments defined by the overidden type - Assignment requestAssignment(Assignment::RequestCommand, _requestAssignmentType, _requestAssignmentPool); - - qDebug() << "Waiting for assignment -" << requestAssignment << "\n"; - - while (true) { - if (usecTimestampNow() - usecTimestamp(&lastRequest) >= ASSIGNMENT_REQUEST_INTERVAL_USECS) { - gettimeofday(&lastRequest, NULL); - - // if we're here we have no assignment, so send a request - nodeList->sendAssignment(requestAssignment); - } - - if (nodeList->getNodeSocket()->receive((sockaddr*) &senderSocket, packetData, &receivedBytes) && - (packetData[0] == PACKET_TYPE_DEPLOY_ASSIGNMENT || packetData[0] == PACKET_TYPE_CREATE_ASSIGNMENT) - && packetVersionMatch(packetData)) { - - // construct the deployed assignment from the packet data - Assignment* deployedAssignment = AssignmentFactory::unpackAssignment(packetData, receivedBytes); - - qDebug() << "Received an assignment -" << *deployedAssignment << "\n"; - - // switch our nodelist domain IP and port to whoever sent us the assignment - if (packetData[0] == PACKET_TYPE_CREATE_ASSIGNMENT) { - - nodeList->setDomainIP(QHostAddress((sockaddr*) &senderSocket)); - nodeList->setDomainPort(ntohs(senderSocket.sin_port)); - - nodeList->setOwnerUUID(deployedAssignment->getUUID()); - - qDebug("Destination IP for assignment is %s\n", nodeList->getDomainIP().toString().toStdString().c_str()); - - // run the deployed assignment - deployedAssignment->run(); - } else { - qDebug("Received a bad destination socket for assignment.\n"); - } - - qDebug("Assignment finished or never started - waiting for new assignment\n"); - - // delete the deployedAssignment - delete deployedAssignment; - - // reset our NodeList by switching back to unassigned and clearing the list - nodeList->setOwnerType(NODE_TYPE_UNASSIGNED); - nodeList->reset(); - - // set the NodeList socket back to blocking - nodeList->getNodeSocket()->setBlocking(true); - - // reset the logging target to the the CHILD_TARGET_NAME - Logging::setTargetName(ASSIGNMENT_CLIENT_TARGET_NAME); - } - } - - return 0; + QTimer* timer = new QTimer(this); + connect(timer, SIGNAL(timeout()), SLOT(sendAssignmentRequest())); + timer->start(ASSIGNMENT_REQUEST_INTERVAL_MSECS); +} + +void AssignmentClient::sendAssignmentRequest() { + NodeList::getInstance()->sendAssignment(_requestAssignment); } diff --git a/assignment-client/src/AssignmentClient.h b/assignment-client/src/AssignmentClient.h index 26f1f952c0..97ccc6e805 100644 --- a/assignment-client/src/AssignmentClient.h +++ b/assignment-client/src/AssignmentClient.h @@ -18,12 +18,10 @@ public: Assignment::Type requestAssignmentType = Assignment::AllTypes, const sockaddr_in& customAssignmentServerSocket = sockaddr_in(), const char* requestAssignmentPool = NULL); - - int exec(); +private slots: + void sendAssignmentRequest(); private: - Assignment::Type _requestAssignmentType; - sockaddr_in _customAssignmentServerSocket; - const char* _requestAssignmentPool; + Assignment _requestAssignment; }; #endif /* defined(__hifi__AssignmentClient__) */ From 76b3bd4e6eb3fad4546cdd235324d0bd7d64ca45 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 2 Dec 2013 12:08:45 -0800 Subject: [PATCH 04/31] Move Hide/Show local voxels to a dedicated thread so that it doesn't slow performance of voxel packet processing --- interface/src/Application.cpp | 4 + interface/src/Application.h | 6 +- interface/src/VoxelHideShowThread.cpp | 46 +++++++++++ interface/src/VoxelHideShowThread.h | 31 ++++++++ interface/src/VoxelSystem.cpp | 109 ++++++++++---------------- interface/src/VoxelSystem.h | 3 + libraries/shared/src/OctalCode.cpp | 3 + 7 files changed, 132 insertions(+), 70 deletions(-) create mode 100644 interface/src/VoxelHideShowThread.cpp create mode 100644 interface/src/VoxelHideShowThread.h diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 43a5e784ed..fd20b968e0 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -140,6 +140,7 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : #endif _stopNetworkReceiveThread(false), _voxelProcessor(), + _voxelHideShowThread(&_voxels), _voxelEditSender(this), _packetCount(0), _packetsPerSecond(0), @@ -329,6 +330,7 @@ void Application::initializeGL() { // create thread for parsing of voxel data independent of the main network and rendering threads _voxelProcessor.initialize(_enableProcessVoxelsThread); _voxelEditSender.initialize(_enableProcessVoxelsThread); + _voxelHideShowThread.initialize(_enableProcessVoxelsThread); if (_enableProcessVoxelsThread) { qDebug("Voxel parsing thread created.\n"); } @@ -1401,6 +1403,7 @@ void Application::terminate() { } _voxelProcessor.terminate(); + _voxelHideShowThread.terminate(); _voxelEditSender.terminate(); } @@ -2249,6 +2252,7 @@ void Application::updateThreads(float deltaTime) { // parse voxel packets if (!_enableProcessVoxelsThread) { _voxelProcessor.threadRoutine(); + _voxelHideShowThread.threadRoutine(); _voxelEditSender.threadRoutine(); } } diff --git a/interface/src/Application.h b/interface/src/Application.h index e2d0820ab9..5034915bd6 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -41,6 +41,7 @@ #include "ViewFrustum.h" #include "VoxelFade.h" #include "VoxelEditPacketSender.h" +#include "VoxelHideShowThread.h" #include "VoxelPacketProcessor.h" #include "VoxelSystem.h" #include "VoxelImporter.h" @@ -442,8 +443,9 @@ private: bool _stopNetworkReceiveThread; bool _enableProcessVoxelsThread; - VoxelPacketProcessor _voxelProcessor; - VoxelEditPacketSender _voxelEditSender; + VoxelPacketProcessor _voxelProcessor; + VoxelHideShowThread _voxelHideShowThread; + VoxelEditPacketSender _voxelEditSender; unsigned char _incomingPacket[MAX_PACKET_SIZE]; int _packetCount; diff --git a/interface/src/VoxelHideShowThread.cpp b/interface/src/VoxelHideShowThread.cpp new file mode 100644 index 0000000000..bb64dd5b08 --- /dev/null +++ b/interface/src/VoxelHideShowThread.cpp @@ -0,0 +1,46 @@ +// +// VoxelHideShowThread.cpp +// interface +// +// Created by Brad Hefta-Gaub on 12/1/13 +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// +// Threaded or non-threaded interface thread for hiding and showing voxels in the local tree. +// + +#include +#include +#include +#include + +#include "Menu.h" +#include "VoxelHideShowThread.h" + +VoxelHideShowThread::VoxelHideShowThread(VoxelSystem* theSystem) : + _theSystem(theSystem) { +} + +bool VoxelHideShowThread::process() { + const uint64_t MSECS_TO_USECS = 1000; + const uint64_t SECS_TO_USECS = 1000 * MSECS_TO_USECS; + const uint64_t FRAME_RATE = 60; + const uint64_t USECS_PER_FRAME = SECS_TO_USECS / FRAME_RATE; // every 60fps + + uint64_t start = usecTimestampNow(); + _theSystem->checkForCulling(); + uint64_t end = usecTimestampNow(); + uint64_t elapsed = end - start; + + bool showExtraDebugging = Menu::getInstance()->isOptionChecked(MenuOption::ExtraDebugging); + if (showExtraDebugging && elapsed > USECS_PER_FRAME) { + printf("VoxelHideShowThread::process()... checkForCulling took %llu\n", elapsed); + } + + if (isStillRunning()) { + if (elapsed < USECS_PER_FRAME) { + uint64_t sleepFor = USECS_PER_FRAME - elapsed; + usleep(sleepFor); + } + } + return isStillRunning(); // keep running till they terminate us +} diff --git a/interface/src/VoxelHideShowThread.h b/interface/src/VoxelHideShowThread.h new file mode 100644 index 0000000000..22df6c299c --- /dev/null +++ b/interface/src/VoxelHideShowThread.h @@ -0,0 +1,31 @@ +// +// VoxelHideShowThread.h +// voxel-server +// +// Created by Brad Hefta-Gaub on 12/1/13 +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// +// Threaded or non-threaded voxel persistence +// + +#ifndef __interface__VoxelHideShowThread__ +#define __interface__VoxelHideShowThread__ + +#include +#include "VoxelSystem.h" + +/// Generalized threaded processor for handling received inbound packets. +class VoxelHideShowThread : public virtual GenericThread { +public: + + VoxelHideShowThread(VoxelSystem* theSystem); + +protected: + /// Implements generic processing behavior for this thread. + virtual bool process(); + +private: + VoxelSystem* _theSystem; +}; + +#endif // __interface__VoxelHideShowThread__ diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index 324f293110..799db030aa 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -592,14 +592,15 @@ float VoxelSystem::getVoxelsBytesReadPerSecondAverage() { } int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) { + bool showTimingDetails = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); + PerformanceWarning warn(showTimingDetails, "VoxelSystem::parseData()",showTimingDetails); unsigned char command = *sourceBuffer; int numBytesPacketHeader = numBytesForPacketHeader(sourceBuffer); switch(command) { case PACKET_TYPE_VOXEL_DATA: { - PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), - "readBitstreamToTree()"); - + PerformanceWarning warn(showTimingDetails, "VoxelSystem::parseData() PACKET_TYPE_VOXEL_DATA part...",showTimingDetails); + unsigned char* dataAt = sourceBuffer + numBytesPacketHeader; VOXEL_PACKET_FLAGS flags = (*(VOXEL_PACKET_FLAGS*)(dataAt)); @@ -641,7 +642,8 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) { VoxelPacketData packetData(packetIsCompressed); packetData.loadFinalizedContent(dataAt, sectionLength); if (Menu::getInstance()->isOptionChecked(MenuOption::ExtraDebugging)) { - qDebug("Got Packet color:%s compressed:%s sequence: %u flight:%d usec size:%d data:%d" + qDebug("VoxelSystem::parseData() ... Got Packet Section" + " color:%s compressed:%s sequence: %u flight:%d usec size:%d data:%d" " subsection:%d sectionLength:%d uncompressed:%d\n", debug::valueOf(packetIsColored), debug::valueOf(packetIsCompressed), sequence, flightTime, numBytes, dataBytes, subsection, sectionLength, packetData.getUncompressedSize()); @@ -657,12 +659,9 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) { } break; } - - if (!_useFastVoxelPipeline || _writeRenderFullVBO) { setupNewVoxelsForDrawing(); } else { - checkForCulling(); setupNewVoxelsForDrawingSingleNode(DONT_BAIL_EARLY); } @@ -689,8 +688,6 @@ void VoxelSystem::setupNewVoxelsForDrawing() { _inSetupNewVoxelsForDrawing = true; - checkForCulling(); // check for out of view and deleted voxels... - bool didWriteFullVBO = _writeRenderFullVBO; if (_tree->isDirty()) { static char buffer[64] = { 0 }; @@ -776,68 +773,44 @@ void VoxelSystem::checkForCulling() { PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "checkForCulling()"); uint64_t start = usecTimestampNow(); - uint64_t sinceLastViewCulling = (start - _lastViewCulling) / 1000; - // These items used to be menu options, we are not defaulting to and only supporting these modes. - bool constantCulling = true; - bool performHideOutOfViewLogic = true; - bool performRemoveOutOfViewLogic = false; - // If the view frustum is no longer changing, but has changed, since last time, then remove nodes that are out of view - if (constantCulling || ( - (sinceLastViewCulling >= std::max((float) _lastViewCullingElapsed, VIEW_CULLING_RATE_IN_MILLISECONDS)) - && !isViewChanging() - ) - ) { - // When we call removeOutOfView() voxels, we don't actually remove the voxels from the VBOs, but we do remove - // them from tree, this makes our tree caclulations faster, but doesn't require us to fully rebuild the VBOs (which - // can be expensive). - if (performHideOutOfViewLogic) { - - // track how long its been since we were last moving. If we have recently moved then only use delta frustums, if - // it's been a long time since we last moved, then go ahead and do a full frustum cull. - if (isViewChanging()) { - _lastViewIsChanging = start; - } - uint64_t sinceLastMoving = (start - _lastViewIsChanging) / 1000; - - bool enoughTime = (sinceLastMoving >= std::max((float) _lastViewCullingElapsed, VIEW_CULLING_RATE_IN_MILLISECONDS)); - - // These has changed events will occur before we stop. So we need to remember this for when we finally have stopped - // moving long enough to be enoughTime - if (hasViewChanged()) { - _hasRecentlyChanged = true; - } - - // If we have recently changed, but it's been enough time since we last moved, then we will do a full frustum - // hide/show culling pass - bool forceFullFrustum = enoughTime && _hasRecentlyChanged; - - // in hide mode, we only track the full frustum culls, because we don't care about the partials. - if (forceFullFrustum) { - _lastViewCulling = start; - _hasRecentlyChanged = false; - } - - hideOutOfView(forceFullFrustum); - - if (forceFullFrustum) { - uint64_t endViewCulling = usecTimestampNow(); - _lastViewCullingElapsed = (endViewCulling - start) / 1000; - } - - } else if (performRemoveOutOfViewLogic) { - _lastViewCulling = start; - removeOutOfView(); - uint64_t endViewCulling = usecTimestampNow(); - _lastViewCullingElapsed = (endViewCulling - start) / 1000; - } - - // Once we call cleanupRemovedVoxels() we do need to rebuild our VBOs (if anything was actually removed). So, - // we should consider putting this someplace else... as this might be able to occur less frequently, and save us on - // VBO reubuilding. Possibly we should do this only if our actual VBO usage crosses some lower boundary. - cleanupRemovedVoxels(); + // track how long its been since we were last moving. If we have recently moved then only use delta frustums, if + // it's been a long time since we last moved, then go ahead and do a full frustum cull. + if (isViewChanging()) { + _lastViewIsChanging = start; } + uint64_t sinceLastMoving = (start - _lastViewIsChanging) / 1000; + + bool enoughTime = (sinceLastMoving >= std::max((float) _lastViewCullingElapsed, VIEW_CULLING_RATE_IN_MILLISECONDS)); + + // These has changed events will occur before we stop. So we need to remember this for when we finally have stopped + // moving long enough to be enoughTime + if (hasViewChanged()) { + _hasRecentlyChanged = true; + } + + // If we have recently changed, but it's been enough time since we last moved, then we will do a full frustum + // hide/show culling pass + bool forceFullFrustum = enoughTime && _hasRecentlyChanged; + + // in hide mode, we only track the full frustum culls, because we don't care about the partials. + if (forceFullFrustum) { + _lastViewCulling = start; + _hasRecentlyChanged = false; + } + + hideOutOfView(forceFullFrustum); + + if (forceFullFrustum) { + uint64_t endViewCulling = usecTimestampNow(); + _lastViewCullingElapsed = (endViewCulling - start) / 1000; + } + + // Once we call cleanupRemovedVoxels() we do need to rebuild our VBOs (if anything was actually removed). So, + // we should consider putting this someplace else... as this might be able to occur less frequently, and save us on + // VBO reubuilding. Possibly we should do this only if our actual VBO usage crosses some lower boundary. + cleanupRemovedVoxels(); uint64_t sinceLastAudit = (start - _lastAudit) / 1000; diff --git a/interface/src/VoxelSystem.h b/interface/src/VoxelSystem.h index d9c672fdf3..5006ec4973 100644 --- a/interface/src/VoxelSystem.h +++ b/interface/src/VoxelSystem.h @@ -40,6 +40,9 @@ struct VoxelShaderVBOData class VoxelSystem : public NodeData, public VoxelNodeDeleteHook, public VoxelNodeUpdateHook, public NodeListHook, public DomainChangeListener { Q_OBJECT + + friend class VoxelHideShowThread; + public: VoxelSystem(float treeScale = TREE_SCALE, int maxVoxels = DEFAULT_MAX_VOXELS_PER_SYSTEM); ~VoxelSystem(); diff --git a/libraries/shared/src/OctalCode.cpp b/libraries/shared/src/OctalCode.cpp index 027a6a4d68..5ac27efd40 100644 --- a/libraries/shared/src/OctalCode.cpp +++ b/libraries/shared/src/OctalCode.cpp @@ -63,6 +63,9 @@ int branchIndexWithDescendant(const unsigned char* ancestorOctalCode, const unsi int parentSections = numberOfThreeBitSectionsInCode(ancestorOctalCode); int branchStartBit = parentSections * 3; + // Note: this does not appear to be "multi-byte length code" safe. When octal codes are larger than 255 bytes + // long, the length code is stored in two bytes. The "1" below appears to assume that the length is always one + // byte long. return sectionValue(descendantOctalCode + 1 + (branchStartBit / 8), branchStartBit % 8); } From 141394a6648cced1cf440df394d9fe75dc3262b8 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 2 Dec 2013 13:34:29 -0800 Subject: [PATCH 05/31] replace UDPSocket with QUDPSocket --- CMakeLists.txt | 1 - animation-server/src/main.cpp | 10 +- assignment-client/src/Agent.cpp | 21 +- assignment-client/src/Agent.h | 2 - assignment-client/src/AssignmentClient.cpp | 6 +- assignment-client/src/AssignmentClient.h | 2 +- assignment-client/src/audio/AudioMixer.cpp | 16 +- assignment-client/src/avatars/AvatarMixer.cpp | 23 +- assignment-client/src/main.cpp | 4 +- .../src/voxels/VoxelScriptingInterface.cpp | 10 +- .../src/voxels/VoxelScriptingInterface.h | 3 + domain-server/src/DomainServer.cpp | 101 ++---- domain-server/src/DomainServer.h | 4 +- interface/src/Application.cpp | 106 +------ interface/src/Application.h | 3 +- interface/src/Audio.cpp | 7 +- interface/src/DataServerClient.cpp | 15 +- interface/src/Environment.cpp | 31 +- interface/src/Environment.h | 6 +- interface/src/PairingHandler.cpp | 25 +- interface/src/VoxelPacketProcessor.cpp | 8 +- interface/src/VoxelPacketProcessor.h | 2 +- interface/src/VoxelSystem.h | 1 - libraries/audio/src/AudioInjectionManager.cpp | 77 ----- libraries/audio/src/AudioInjectionManager.h | 36 --- libraries/audio/src/AudioInjector.cpp | 137 -------- libraries/audio/src/AudioInjector.h | 73 ----- .../audio/src/InjectedAudioRingBuffer.cpp | 2 + libraries/audio/src/InjectedAudioRingBuffer.h | 2 - libraries/shared/src/HifiSockAddr.cpp | 110 +++++++ libraries/shared/src/HifiSockAddr.h | 48 +++ libraries/shared/src/Logging.cpp | 27 +- libraries/shared/src/Logging.h | 6 +- libraries/shared/src/NetworkPacket.cpp | 12 +- libraries/shared/src/NetworkPacket.h | 12 +- libraries/shared/src/Node.cpp | 51 +-- libraries/shared/src/Node.h | 21 +- libraries/shared/src/NodeList.cpp | 154 +++++---- libraries/shared/src/NodeList.h | 45 ++- libraries/shared/src/PacketSender.cpp | 8 +- libraries/shared/src/PacketSender.h | 4 +- .../shared/src/ReceivedPacketProcessor.cpp | 6 +- .../shared/src/ReceivedPacketProcessor.h | 4 +- libraries/shared/src/UDPSocket.cpp | 293 ------------------ libraries/shared/src/UDPSocket.h | 53 ---- .../src/VoxelSendThread.cpp | 22 +- .../voxel-server-library/src/VoxelServer.cpp | 14 +- .../src/VoxelServerPacketProcessor.cpp | 9 +- .../src/VoxelServerPacketProcessor.h | 2 +- libraries/voxels/src/JurisdictionListener.cpp | 6 +- libraries/voxels/src/JurisdictionListener.h | 2 +- libraries/voxels/src/JurisdictionSender.cpp | 6 +- libraries/voxels/src/JurisdictionSender.h | 2 +- .../voxels/src/VoxelEditPacketSender.cpp | 2 +- pairing-server/CMakeLists.txt | 4 + pairing-server/src/main.cpp | 29 +- space-server/CMakeLists.txt | 13 - space-server/example.data.txt | 2 - space-server/src/TreeNode.cpp | 20 -- space-server/src/TreeNode.h | 26 -- space-server/src/main.cpp | 160 ---------- 61 files changed, 521 insertions(+), 1386 deletions(-) delete mode 100644 libraries/audio/src/AudioInjectionManager.cpp delete mode 100644 libraries/audio/src/AudioInjectionManager.h delete mode 100644 libraries/audio/src/AudioInjector.cpp delete mode 100644 libraries/audio/src/AudioInjector.h create mode 100644 libraries/shared/src/HifiSockAddr.cpp create mode 100644 libraries/shared/src/HifiSockAddr.h delete mode 100644 libraries/shared/src/UDPSocket.cpp delete mode 100644 libraries/shared/src/UDPSocket.h delete mode 100644 space-server/CMakeLists.txt delete mode 100644 space-server/example.data.txt delete mode 100644 space-server/src/TreeNode.cpp delete mode 100644 space-server/src/TreeNode.h delete mode 100644 space-server/src/main.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 7f43bbc3af..c533f360f0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,5 +17,4 @@ add_subdirectory(assignment-client) add_subdirectory(domain-server) add_subdirectory(interface) add_subdirectory(pairing-server) -add_subdirectory(space-server) add_subdirectory(voxel-edit) \ No newline at end of file diff --git a/animation-server/src/main.cpp b/animation-server/src/main.cpp index e9e8a9857d..281c761c00 100644 --- a/animation-server/src/main.cpp +++ b/animation-server/src/main.cpp @@ -841,7 +841,7 @@ int main(int argc, const char * argv[]) pthread_t animateVoxelThread; pthread_create(&animateVoxelThread, NULL, animateVoxels, NULL); - sockaddr nodePublicAddress; + HifiSockAddr nodeSockAddr; unsigned char* packetData = new unsigned char[MAX_PACKET_SIZE]; ssize_t receivedBytes; @@ -858,15 +858,17 @@ int main(int argc, const char * argv[]) } // Nodes sending messages to us... - if (nodeList->getNodeSocket()->receive(&nodePublicAddress, packetData, &receivedBytes) && + if ((receivedBytes = nodeList->getNodeSocket().readDatagram((char*) packetData, MAX_PACKET_SIZE, + nodeSockAddr.getAddressPointer(), + nodeSockAddr.getPortPointer())) && packetVersionMatch(packetData)) { if (packetData[0] == PACKET_TYPE_VOXEL_JURISDICTION) { if (::jurisdictionListener) { - ::jurisdictionListener->queueReceivedPacket(nodePublicAddress, packetData, receivedBytes); + ::jurisdictionListener->queueReceivedPacket(nodeSockAddr, packetData, receivedBytes); } } - NodeList::getInstance()->processNodeData(&nodePublicAddress, packetData, receivedBytes); + NodeList::getInstance()->processNodeData(nodeSockAddr, packetData, receivedBytes); } } diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index 2492138857..bedaab87c4 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -51,8 +51,6 @@ void Agent::run() { const char AGENT_NODE_TYPES_OF_INTEREST[1] = { NODE_TYPE_VOXEL_SERVER }; nodeList->setNodeTypesOfInterest(AGENT_NODE_TYPES_OF_INTEREST, sizeof(AGENT_NODE_TYPES_OF_INTEREST)); - - nodeList->getNodeSocket()->setBlocking(false); // figure out the URL for the script for this agent assignment QString scriptURLString("http://%1:8080/assignment/%2"); @@ -90,11 +88,6 @@ void Agent::run() { // let the VoxelPacketSender know how frequently we plan to call it voxelScripter.getVoxelPacketSender()->setProcessCallIntervalHint(VISUAL_DATA_CALLBACK_USECS); - // hook in a constructor for audio injectorss - AudioInjector scriptedAudioInjector(BUFFER_LENGTH_SAMPLES_PER_CHANNEL); - QScriptValue audioInjectorValue = engine.newQObject(&scriptedAudioInjector); - engine.globalObject().setProperty("AudioInjector", audioInjectorValue); - qDebug() << "Downloaded script:" << scriptContents << "\n"; QScriptValue result = engine.evaluate(scriptContents); qDebug() << "Evaluated script.\n"; @@ -109,7 +102,8 @@ void Agent::run() { timeval lastDomainServerCheckIn = {}; - sockaddr_in senderAddress; + + HifiSockAddr senderSockAddr; unsigned char receivedData[MAX_PACKET_SIZE]; ssize_t receivedBytes; @@ -153,14 +147,17 @@ void Agent::run() { qDebug() << "Uncaught exception at line" << line << ":" << engine.uncaughtException().toString() << "\n"; } - while (NodeList::getInstance()->getNodeSocket()->receive((sockaddr*) &senderAddress, receivedData, &receivedBytes) - && packetVersionMatch(receivedData)) { + while ((receivedBytes = NodeList::getInstance()->getNodeSocket().readDatagram((char*) receivedBytes, + MAX_PACKET_SIZE, + senderSockAddr.getAddressPointer(), + senderSockAddr.getPortPointer())) + && packetVersionMatch(receivedData)) { if (receivedData[0] == PACKET_TYPE_VOXEL_JURISDICTION) { - voxelScripter.getJurisdictionListener()->queueReceivedPacket((sockaddr&) senderAddress, + voxelScripter.getJurisdictionListener()->queueReceivedPacket(senderSockAddr, receivedData, receivedBytes); } else { - NodeList::getInstance()->processNodeData((sockaddr*) &senderAddress, receivedData, receivedBytes); + NodeList::getInstance()->processNodeData(senderSockAddr, receivedData, receivedBytes); } } } diff --git a/assignment-client/src/Agent.h b/assignment-client/src/Agent.h index 552910e04d..2ad7eba1e6 100644 --- a/assignment-client/src/Agent.h +++ b/assignment-client/src/Agent.h @@ -15,7 +15,6 @@ #include #include -#include #include class Agent : public Assignment { @@ -33,7 +32,6 @@ private: static QScriptValue AudioInjectorConstructor(QScriptContext *context, QScriptEngine *engine); bool volatile _shouldStop; - std::vector _audioInjectors; }; #endif /* defined(__hifi__Agent__) */ diff --git a/assignment-client/src/AssignmentClient.cpp b/assignment-client/src/AssignmentClient.cpp index 92d394f41a..f694795466 100644 --- a/assignment-client/src/AssignmentClient.cpp +++ b/assignment-client/src/AssignmentClient.cpp @@ -23,7 +23,7 @@ const long long ASSIGNMENT_REQUEST_INTERVAL_MSECS = 1 * 1000; AssignmentClient::AssignmentClient(int &argc, char **argv, Assignment::Type requestAssignmentType, - const sockaddr_in& customAssignmentServerSocket, + const HifiSockAddr& customAssignmentServerSocket, const char* requestAssignmentPool) : QCoreApplication(argc, argv), _requestAssignment(Assignment::RequestCommand, requestAssignmentType, requestAssignmentPool) @@ -35,8 +35,8 @@ AssignmentClient::AssignmentClient(int &argc, char **argv, NodeList* nodeList = NodeList::createInstance(NODE_TYPE_UNASSIGNED); // set the custom assignment socket if we have it - if (customAssignmentServerSocket.sin_addr.s_addr != 0) { - nodeList->setAssignmentServerSocket((sockaddr*) &customAssignmentServerSocket); + if (!customAssignmentServerSocket.isNull()) { + nodeList->setAssignmentServerSocket(customAssignmentServerSocket); } // call a timer function every ASSIGNMENT_REQUEST_INTERVAL_MSECS to ask for assignment, if required diff --git a/assignment-client/src/AssignmentClient.h b/assignment-client/src/AssignmentClient.h index 97ccc6e805..e7072e816a 100644 --- a/assignment-client/src/AssignmentClient.h +++ b/assignment-client/src/AssignmentClient.h @@ -16,7 +16,7 @@ class AssignmentClient : public QCoreApplication { public: AssignmentClient(int &argc, char **argv, Assignment::Type requestAssignmentType = Assignment::AllTypes, - const sockaddr_in& customAssignmentServerSocket = sockaddr_in(), + const HifiSockAddr& customAssignmentServerSocket = HifiSockAddr(), const char* requestAssignmentPool = NULL); private slots: void sendAssignmentRequest(); diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index c8897fe2b1..0d11a63344 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -235,10 +235,7 @@ void AudioMixer::run() { unsigned char packetData[MAX_PACKET_SIZE] = {}; - sockaddr* nodeAddress = new sockaddr; - - // make sure our node socket is non-blocking - nodeList->getNodeSocket()->setBlocking(false); + HifiSockAddr nodeSockAddr; int nextFrame = 0; timeval startTime; @@ -301,7 +298,9 @@ void AudioMixer::run() { prepareMixForListeningNode(&(*node)); memcpy(clientPacket + numBytesPacketHeader, _clientSamples, sizeof(_clientSamples)); - nodeList->getNodeSocket()->send(node->getActiveSocket(), clientPacket, sizeof(clientPacket)); + nodeList->getNodeSocket().writeDatagram((char*) clientPacket, sizeof(clientPacket), + node->getActiveSocket()->getAddress(), + node->getActiveSocket()->getPort()); } } @@ -313,7 +312,8 @@ void AudioMixer::run() { } // pull any new audio data from nodes off of the network stack - while (nodeList->getNodeSocket()->receive(nodeAddress, packetData, &receivedBytes) && + while ((receivedBytes = nodeList->getNodeSocket().readDatagram((char*) packetData, MAX_PACKET_SIZE, + nodeSockAddr.getAddressPointer(), nodeSockAddr.getPortPointer())) && packetVersionMatch(packetData)) { if (packetData[0] == PACKET_TYPE_MICROPHONE_AUDIO_NO_ECHO || packetData[0] == PACKET_TYPE_MICROPHONE_AUDIO_WITH_ECHO @@ -325,7 +325,7 @@ void AudioMixer::run() { Node* matchingNode = nodeList->nodeWithUUID(nodeUUID); if (matchingNode) { - nodeList->updateNodeWithData(matchingNode, nodeAddress, packetData, receivedBytes); + nodeList->updateNodeWithData(matchingNode, nodeSockAddr, packetData, receivedBytes); if (!matchingNode->getActiveSocket()) { // we don't have an active socket for this node, but they're talking to us @@ -335,7 +335,7 @@ void AudioMixer::run() { } } else { // let processNodeData handle it. - nodeList->processNodeData(nodeAddress, packetData, receivedBytes); + nodeList->processNodeData(nodeSockAddr, packetData, receivedBytes); } } diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index b13c92e0ed..787771a269 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -46,7 +46,7 @@ void attachAvatarDataToNode(Node* newNode) { // 3) if we need to rate limit the amount of data we send, we can use a distance weighted "semi-random" function to // determine which avatars are included in the packet stream // 4) we should optimize the avatar data format to be more compact (100 bytes is pretty wasteful). -void broadcastAvatarData(NodeList* nodeList, const QUuid& receiverUUID, sockaddr* receiverAddress) { +void broadcastAvatarData(NodeList* nodeList, const QUuid& receiverUUID, const HifiSockAddr& receiverSockAddr) { static unsigned char broadcastPacketBuffer[MAX_PACKET_SIZE]; static unsigned char avatarDataBuffer[MAX_PACKET_SIZE]; unsigned char* broadcastPacket = (unsigned char*)&broadcastPacketBuffer[0]; @@ -68,7 +68,8 @@ void broadcastAvatarData(NodeList* nodeList, const QUuid& receiverUUID, sockaddr } else { packetsSent++; //printf("packetsSent=%d packetLength=%d\n", packetsSent, packetLength); - nodeList->getNodeSocket()->send(receiverAddress, broadcastPacket, currentBufferPosition - broadcastPacket); + nodeList->getNodeSocket().writeDatagram((char*) broadcastPacket, currentBufferPosition - broadcastPacket, + receiverSockAddr.getAddress(), receiverSockAddr.getPort()); // reset the packet currentBufferPosition = broadcastPacket + numHeaderBytes; @@ -83,7 +84,8 @@ void broadcastAvatarData(NodeList* nodeList, const QUuid& receiverUUID, sockaddr } packetsSent++; //printf("packetsSent=%d packetLength=%d\n", packetsSent, packetLength); - nodeList->getNodeSocket()->send(receiverAddress, broadcastPacket, currentBufferPosition - broadcastPacket); + nodeList->getNodeSocket().writeDatagram((char*) broadcastPacket, currentBufferPosition - broadcastPacket, + receiverSockAddr.getAddress(), receiverSockAddr.getPort()); } AvatarMixer::AvatarMixer(const unsigned char* dataBuffer, int numBytes) : Assignment(dataBuffer, numBytes) { @@ -103,7 +105,7 @@ void AvatarMixer::run() { nodeList->startSilentNodeRemovalThread(); - sockaddr nodeAddress = {}; + HifiSockAddr nodeSockAddr; ssize_t receivedBytes = 0; unsigned char packetData[MAX_PACKET_SIZE]; @@ -127,7 +129,8 @@ void AvatarMixer::run() { nodeList->possiblyPingInactiveNodes(); - if (nodeList->getNodeSocket()->receive(&nodeAddress, packetData, &receivedBytes) && + if (nodeList->getNodeSocket().readDatagram((char*) packetData, MAX_PACKET_SIZE, + nodeSockAddr.getAddressPointer(), nodeSockAddr.getPortPointer()) && packetVersionMatch(packetData)) { switch (packetData[0]) { case PACKET_TYPE_HEAD_DATA: @@ -139,12 +142,12 @@ void AvatarMixer::run() { if (avatarNode) { // parse positional data from an node - nodeList->updateNodeWithData(avatarNode, &nodeAddress, packetData, receivedBytes); + nodeList->updateNodeWithData(avatarNode, nodeSockAddr, packetData, receivedBytes); } else { break; } case PACKET_TYPE_INJECT_AUDIO: - broadcastAvatarData(nodeList, nodeUUID, &nodeAddress); + broadcastAvatarData(nodeList, nodeUUID, nodeSockAddr); break; case PACKET_TYPE_KILL_NODE: case PACKET_TYPE_AVATAR_URLS: @@ -154,14 +157,16 @@ void AvatarMixer::run() { // let everyone else know about the update for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { if (node->getActiveSocket() && node->getUUID() != nodeUUID) { - nodeList->getNodeSocket()->send(node->getActiveSocket(), packetData, receivedBytes); + nodeList->getNodeSocket().writeDatagram((char*) packetData, receivedBytes, + node->getActiveSocket()->getAddress(), + node->getActiveSocket()->getPort()); } } // let node kills fall through to default behavior default: // hand this off to the NodeList - nodeList->processNodeData(&nodeAddress, packetData, receivedBytes); + nodeList->processNodeData(nodeSockAddr, packetData, receivedBytes); break; } } diff --git a/assignment-client/src/main.cpp b/assignment-client/src/main.cpp index 5f98f4f856..cef77610c4 100644 --- a/assignment-client/src/main.cpp +++ b/assignment-client/src/main.cpp @@ -28,7 +28,7 @@ const char PARENT_TARGET_NAME[] = "assignment-client-monitor"; pid_t* childForks = NULL; -sockaddr_in customAssignmentSocket = {}; +HifiSockAddr customAssignmentSocket; int numForks = 0; Assignment::Type overiddenAssignmentType = Assignment::AllTypes; const char* assignmentPool = NULL; @@ -130,7 +130,7 @@ int main(int argc, char* argv[]) { customAssignmentServerHostname = LOCAL_ASSIGNMENT_SERVER_HOSTNAME; } - ::customAssignmentSocket = socketForHostnameAndHostOrderPort(customAssignmentServerHostname, assignmentServerPort); + ::customAssignmentSocket = HifiSockAddr(customAssignmentServerHostname, assignmentServerPort); } const char ASSIGNMENT_TYPE_OVVERIDE_OPTION[] = "-t"; diff --git a/assignment-client/src/voxels/VoxelScriptingInterface.cpp b/assignment-client/src/voxels/VoxelScriptingInterface.cpp index 1801c621c4..b967c23187 100644 --- a/assignment-client/src/voxels/VoxelScriptingInterface.cpp +++ b/assignment-client/src/voxels/VoxelScriptingInterface.cpp @@ -27,11 +27,13 @@ void VoxelScriptingInterface::queueVoxelAdd(float x, float y, float z, float sca void VoxelScriptingInterface::queueDestructiveVoxelAdd(float x, float y, float z, float scale, uchar red, uchar green, uchar blue) { - // setup a VoxelDetail struct with the data - VoxelDetail addVoxelDetail = {x, y, z, scale, red, green, blue}; +// // setup a VoxelDetail struct with the data +// VoxelDetail addVoxelDetail = {x, y, z, scale, red, green, blue}; +// +// // queue the destructive add +// queueVoxelAdd(PACKET_TYPE_SET_VOXEL_DESTRUCTIVE, addVoxelDetail); - // queue the destructive add - queueVoxelAdd(PACKET_TYPE_SET_VOXEL_DESTRUCTIVE, addVoxelDetail); + _voxelTree.createVoxel(x, y, z, scale, red, green, blue); } void VoxelScriptingInterface::queueVoxelDelete(float x, float y, float z, float scale) { diff --git a/assignment-client/src/voxels/VoxelScriptingInterface.h b/assignment-client/src/voxels/VoxelScriptingInterface.h index 473cf3035c..fc1426ebbc 100644 --- a/assignment-client/src/voxels/VoxelScriptingInterface.h +++ b/assignment-client/src/voxels/VoxelScriptingInterface.h @@ -13,6 +13,7 @@ #include #include +#include /// handles scripting of voxel commands from JS passed to assigned clients class VoxelScriptingInterface : public QObject { @@ -22,6 +23,7 @@ public: VoxelEditPacketSender* getVoxelPacketSender() { return &_voxelPacketSender; } JurisdictionListener* getJurisdictionListener() { return &_jurisdictionListener; } + VoxelTree* getVoxelTree() { return &_voxelTree; } public slots: /// queues the creation of a voxel which will be sent by calling process on the PacketSender /// \param x the x-coordinate of the voxel (in VS space) @@ -105,6 +107,7 @@ private: /// attached VoxelEditPacketSender that handles queuing and sending of packets to VS VoxelEditPacketSender _voxelPacketSender; JurisdictionListener _jurisdictionListener; + VoxelTree _voxelTree; void queueVoxelAdd(PACKET_TYPE addPacketType, VoxelDetail& addVoxelDetails); }; diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 792942f846..9aba991f16 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -30,14 +30,11 @@ void DomainServer::setDomainServerInstance(DomainServer* domainServer) { domainServerInstance = domainServer; } -QJsonObject jsonForSocket(sockaddr* socket) { +QJsonObject jsonForSocket(const HifiSockAddr& socket) { QJsonObject socketJSON; - if (socket->sa_family == AF_INET) { - sockaddr_in* socketIPv4 = (sockaddr_in*) socket; - socketJSON["ip"] = QString(inet_ntoa(socketIPv4->sin_addr)); - socketJSON["port"] = (int) ntohs(socketIPv4->sin_port); - } + socketJSON["ip"] = socket.getAddress().toString(); + socketJSON["port"] = ntohs(socket.getPort()); return socketJSON; } @@ -288,8 +285,8 @@ unsigned char* DomainServer::addNodeToBroadcastPacket(unsigned char* currentPosi memcpy(currentPosition, rfcUUID.constData(), rfcUUID.size()); currentPosition += rfcUUID.size(); - currentPosition += packSocket(currentPosition, nodeToAdd->getPublicSocket()); - currentPosition += packSocket(currentPosition, nodeToAdd->getLocalSocket()); + currentPosition += HifiSockAddr::packSockAddr(currentPosition, nodeToAdd->getPublicSocket()); + currentPosition += HifiSockAddr::packSockAddr(currentPosition, nodeToAdd->getLocalSocket()); // return the new unsigned char * for broadcast packet return currentPosition; @@ -506,15 +503,15 @@ void DomainServer::removeAssignmentFromQueue(Assignment* removableAssignment) { _assignmentQueueMutex.unlock(); } -bool DomainServer::checkInWithUUIDMatchesExistingNode(sockaddr* nodePublicSocket, - sockaddr* nodeLocalSocket, +bool DomainServer::checkInWithUUIDMatchesExistingNode(const HifiSockAddr& nodePublicSocket, + const HifiSockAddr& nodeLocalSocket, const QUuid& checkInUUID) { NodeList* nodeList = NodeList::getInstance(); for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { if (node->getLinkedData() - && socketMatch(node->getPublicSocket(), nodePublicSocket) - && socketMatch(node->getLocalSocket(), nodeLocalSocket) + && nodePublicSocket == node->getPublicSocket() + && nodeLocalSocket == node->getLocalSocket() && node->getUUID() == checkInUUID) { // this is a matching existing node if the public socket, local socket, and UUID match return true; @@ -588,9 +585,11 @@ int DomainServer::run() { unsigned char* currentBufferPos; unsigned char* startPointer; - sockaddr_in senderAddress, nodePublicAddress, nodeLocalAddress; - nodePublicAddress.sin_family = AF_INET; - nodeLocalAddress.sin_family = AF_INET; + QHostAddress senderAddress; + quint16 senderPort; + HifiSockAddr nodePublicAddress, nodeLocalAddress; + + nodeList->startSilentNodeRemovalThread(); @@ -614,7 +613,7 @@ int DomainServer::run() { gettimeofday(&startTime, NULL); while (true) { - while (nodeList->getNodeSocket()->receive((sockaddr *)&senderAddress, packetData, &receivedBytes) && + while (nodeList->getNodeSocket().readDatagram((char*) packetData, MAX_PACKET_SIZE, &senderAddress, &senderPort) && packetVersionMatch(packetData)) { if (packetData[0] == PACKET_TYPE_DOMAIN_REPORT_FOR_DUTY || packetData[0] == PACKET_TYPE_DOMAIN_LIST_REQUEST) { // this is an RFD or domain list request packet, and there is a version match @@ -627,23 +626,23 @@ int DomainServer::run() { QUuid nodeUUID = QUuid::fromRfc4122(QByteArray(((char*) packetData + packetIndex), NUM_BYTES_RFC4122_UUID)); packetIndex += NUM_BYTES_RFC4122_UUID; - int numBytesPrivateSocket = unpackSocket(packetData + packetIndex, (sockaddr*) &nodePublicAddress); + int numBytesPrivateSocket = HifiSockAddr::unpackSockAddr(packetData + packetIndex, nodePublicAddress); packetIndex += numBytesPrivateSocket; - if (nodePublicAddress.sin_addr.s_addr == 0) { + if (nodePublicAddress.getAddress().isNull() == 0) { // this node wants to use us its STUN server // so set the node public address to whatever we perceive the public address to be - nodePublicAddress = senderAddress; + nodePublicAddress.setAddress(senderAddress); // if the sender is on our box then leave its public address to 0 so that // other users attempt to reach it on the same address they have for the domain-server - if (senderAddress.sin_addr.s_addr == htonl(INADDR_LOOPBACK)) { - nodePublicAddress.sin_addr.s_addr = 0; + if (senderAddress.isLoopback()) { + nodePublicAddress.setAddress(QHostAddress()); } } - int numBytesPublicSocket = unpackSocket(packetData + packetIndex, (sockaddr*) &nodeLocalAddress); + int numBytesPublicSocket = HifiSockAddr::unpackSockAddr(packetData + packetIndex, nodeLocalAddress); packetIndex += numBytesPublicSocket; const char STATICALLY_ASSIGNED_NODES[3] = { @@ -656,14 +655,14 @@ int DomainServer::run() { if (memchr(STATICALLY_ASSIGNED_NODES, nodeType, sizeof(STATICALLY_ASSIGNED_NODES)) == NULL || ((matchingStaticAssignment = matchingStaticAssignmentForCheckIn(nodeUUID, nodeType)) - || checkInWithUUIDMatchesExistingNode((sockaddr*) &nodePublicAddress, - (sockaddr*) &nodeLocalAddress, + || checkInWithUUIDMatchesExistingNode(nodePublicAddress, + nodeLocalAddress, nodeUUID))) { Node* checkInNode = nodeList->addOrUpdateNode(nodeUUID, nodeType, - (sockaddr*) &nodePublicAddress, - (sockaddr*) &nodeLocalAddress); + nodePublicAddress, + nodeLocalAddress); if (matchingStaticAssignment) { // this was a newly added node with a matching static assignment @@ -691,7 +690,7 @@ int DomainServer::run() { if (numInterestTypes > 0) { // 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) && + if (node->getUUID() != nodeUUID && memchr(nodeTypesOfInterest, node->getType(), numInterestTypes)) { // don't send avatar nodes to other avatars, that will come from avatar mixer @@ -708,9 +707,9 @@ int DomainServer::run() { checkInNode->setLastHeardMicrostamp(timeNow); // send the constructed list back to this node - nodeList->getNodeSocket()->send((sockaddr*)&senderAddress, - broadcastPacket, - (currentBufferPos - startPointer) + numHeaderBytes); + nodeList->getNodeSocket().writeDatagram((char*) broadcastPacket, + (currentBufferPos - startPointer) + numHeaderBytes, + senderAddress, senderPort); } } else if (packetData[0] == PACKET_TYPE_REQUEST_ASSIGNMENT) { @@ -732,9 +731,8 @@ int DomainServer::run() { int numHeaderBytes = populateTypeAndVersion(broadcastPacket, PACKET_TYPE_CREATE_ASSIGNMENT); int numAssignmentBytes = assignmentToDeploy->packToBuffer(broadcastPacket + numHeaderBytes); - nodeList->getNodeSocket()->send((sockaddr*) &senderAddress, - broadcastPacket, - numHeaderBytes + numAssignmentBytes); + nodeList->getNodeSocket().writeDatagram((char*) broadcastPacket, numHeaderBytes + numAssignmentBytes, + senderAddress, senderPort); if (assignmentToDeploy->getNumberOfInstances() == 0) { // there are no more instances of this script to send out, delete it @@ -743,43 +741,6 @@ int DomainServer::run() { } } - } else if (packetData[0] == PACKET_TYPE_CREATE_ASSIGNMENT) { - // this is a create assignment likely recieved from a server needed more clients to help with load - - // unpack it - Assignment* createAssignment = new Assignment(packetData, receivedBytes); - - qDebug() << "Received a create assignment -" << *createAssignment << "\n"; - - // make sure we have a matching node with the UUID packed with the assignment - // 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->getLinkedData() - && socketMatch((sockaddr*) &senderAddress, node->getPublicSocket()) - && ((Assignment*) node->getLinkedData())->getUUID() == createAssignment->getUUID()) { - - // give the create assignment a new UUID - createAssignment->resetUUID(); - - // add the assignment at the back of the queue - _assignmentQueueMutex.lock(); - _assignmentQueue.push_back(createAssignment); - _assignmentQueueMutex.unlock(); - - // find the first available spot in the static assignments and put this assignment there - for (int i = 0; i < MAX_STATIC_ASSIGNMENT_FILE_ASSIGNMENTS; i++) { - if (_staticAssignments[i].getUUID().isNull()) { - _staticAssignments[i] = *createAssignment; - - // we've stuck the assignment in, break out - break; - } - } - - // we found the matching node that asked for create assignment, break out - break; - } - } } } diff --git a/domain-server/src/DomainServer.h b/domain-server/src/DomainServer.h index 45730847ac..755f73485c 100644 --- a/domain-server/src/DomainServer.h +++ b/domain-server/src/DomainServer.h @@ -45,7 +45,9 @@ private: Assignment* matchingStaticAssignmentForCheckIn(const QUuid& checkInUUID, NODE_TYPE nodeType); Assignment* deployableAssignmentForRequest(Assignment& requestAssignment); void removeAssignmentFromQueue(Assignment* removableAssignment); - bool checkInWithUUIDMatchesExistingNode(sockaddr* nodePublicSocket, sockaddr* nodeLocalSocket, const QUuid& checkInUUI); + bool checkInWithUUIDMatchesExistingNode(const HifiSockAddr& nodePublicSocket, + const HifiSockAddr& nodeLocalSocket, + const QUuid& checkInUUI); void possiblyAddStaticAssignmentsBackToQueueAfterRestart(timeval* startTime); void addReleasedAssignmentBackToQueue(Assignment* releasedAssignment); diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 58629df41e..84f72242c4 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -19,6 +19,7 @@ #include #endif +#include #include #include @@ -47,8 +48,6 @@ #include #include -#include -#include #include #include #include @@ -172,9 +171,6 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : // network receive thread and voxel parsing thread are both controlled by the --nonblocking command line _enableProcessVoxelsThread = _enableNetworkThread = !cmdOptionExists(argc, constArgv, "--nonblocking"); - if (!_enableNetworkThread) { - NodeList::getInstance()->getNodeSocket()->setBlocking(false); - } // setup QSettings #ifdef Q_OS_MAC @@ -1463,8 +1459,9 @@ void Application::checkBandwidthMeterClick() { // ... to be called upon button release if (Menu::getInstance()->isOptionChecked(MenuOption::Bandwidth) && - glm::compMax(glm::abs(glm::ivec2(_mouseX - _mouseDragStartedX, _mouseY - _mouseDragStartedY))) <= BANDWIDTH_METER_CLICK_MAX_DRAG_LENGTH && - _bandwidthMeter.isWithinArea(_mouseX, _mouseY, _glWidget->width(), _glWidget->height())) { + glm::compMax(glm::abs(glm::ivec2(_mouseX - _mouseDragStartedX, _mouseY - _mouseDragStartedY))) + <= BANDWIDTH_METER_CLICK_MAX_DRAG_LENGTH + && _bandwidthMeter.isWithinArea(_mouseX, _mouseY, _glWidget->width(), _glWidget->height())) { // The bandwidth meter is visible, the click didn't get dragged too far and // we actually hit the bandwidth meter @@ -2661,7 +2658,6 @@ void Application::queryVoxels() { qDebug("perServerPPS: %d perUnknownServer: %d\n", perServerPPS, perUnknownServer); } - UDPSocket* nodeSocket = NodeList::getInstance()->getNodeSocket(); for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { // only send to the NodeTypes that are NODE_TYPE_VOXEL_SERVER if (node->getActiveSocket() != NULL && node->getType() == NODE_TYPE_VOXEL_SERVER) { @@ -2747,7 +2743,8 @@ void Application::queryVoxels() { int packetLength = endOfVoxelQueryPacket - voxelQueryPacket; - nodeSocket->send(node->getActiveSocket(), voxelQueryPacket, packetLength); + nodeList->getNodeSocket().writeDatagram((char*) voxelQueryPacket, packetLength, + node->getActiveSocket()->getAddress(), node->getActiveSocket()->getPort()); // Feed number of bytes to corresponding channel of the bandwidth meter _bandwidthMeter.outputStream(BandwidthMeter::VOXELS).updateValue(packetLength); @@ -4034,62 +4031,6 @@ void Application::renderViewFrustum(ViewFrustum& viewFrustum) { } } -void Application::injectVoxelAddedSoundEffect() { - AudioInjector* voxelInjector = AudioInjectionManager::injectorWithCapacity(11025); - - if (voxelInjector) { - voxelInjector->setPosition(glm::vec3(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z)); - //voxelInjector->setBearing(-1 * _myAvatar.getAbsoluteHeadYaw()); - voxelInjector->setVolume (16 * pow (_mouseVoxel.s, 2) / .0000001); //255 is max, and also default value - - /* for (int i = 0; i - < 22050; i++) { - if (i % 4 == 0) { - voxelInjector->addSample(4000); - } else if (i % 4 == 1) { - voxelInjector->addSample(0); - } else if (i % 4 == 2) { - voxelInjector->addSample(-4000); - } else { - voxelInjector->addSample(0); - } - */ - - const float BIG_VOXEL_MIN_SIZE = .01f; - - for (int i = 0; i < 11025; i++) { - - /* - A440 square wave - if (sin(i * 2 * PIE / 50)>=0) { - voxelInjector->addSample(4000); - } else { - voxelInjector->addSample(-4000); - } - */ - - if (_mouseVoxel.s > BIG_VOXEL_MIN_SIZE) { - voxelInjector->addSample(20000 * sin((i * 2 * PIE) / (500 * sin((i + 1) / 200)))); - } else { - voxelInjector->addSample(16000 * sin(i / (1.5 * log (_mouseVoxel.s / .0001) * ((i + 11025) / 5512.5)))); //808 - } - } - - //voxelInjector->addSample(32500 * sin(i/(2 * 1 * ((i+5000)/5512.5)))); //80 - //voxelInjector->addSample(20000 * sin(i/(6 * (_mouseVoxel.s/.001) *((i+5512.5)/5512.5)))); //808 - //voxelInjector->addSample(20000 * sin(i/(6 * ((i+5512.5)/5512.5)))); //808 - //voxelInjector->addSample(4000 * sin(i * 2 * PIE /50)); //A440 sine wave - //voxelInjector->addSample(4000 * sin(i * 2 * PIE /50) * sin (i/500)); //A440 sine wave with amplitude modulation - - //FM library - //voxelInjector->addSample(20000 * sin((i * 2 * PIE) /(500*sin((i+1)/200)))); //FM 1 dubstep - //voxelInjector->addSample(20000 * sin((i * 2 * PIE) /(300*sin((i+1)/5.0)))); //FM 2 flange sweep - //voxelInjector->addSample(10000 * sin((i * 2 * PIE) /(500*sin((i+1)/500.0)))); //FM 3 resonant pulse - - AudioInjectionManager::threadInjector(voxelInjector); - } -} - bool Application::maybeEditVoxelUnderCursor() { if (Menu::getInstance()->isOptionChecked(MenuOption::VoxelAddMode) || Menu::getInstance()->isOptionChecked(MenuOption::VoxelColorMode)) { @@ -4114,9 +4055,6 @@ bool Application::maybeEditVoxelUnderCursor() { fade.voxelDetails.s = _mouseVoxel.s + slightlyBigger + slightlyBigger; _voxelFades.push_back(fade); - // inject a sound effect - injectVoxelAddedSoundEffect(); - // remember the position for drag detection _justEditedVoxel = true; @@ -4149,21 +4087,6 @@ void Application::deleteVoxelUnderCursor() { // delete it locally to see the effect immediately (and in case no voxel server is present) _voxels.deleteVoxelAt(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); - AudioInjector* voxelInjector = AudioInjectionManager::injectorWithCapacity(5000); - - if (voxelInjector) { - voxelInjector->setPosition(glm::vec3(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z)); - //voxelInjector->setBearing(0); //straight down the z axis - voxelInjector->setVolume (255); //255 is max, and also default value - - - for (int i = 0; i < 5000; i++) { - voxelInjector->addSample(10000 * sin((i * 2 * PIE) / (500 * sin((i + 1) / 500.0)))); //FM 3 resonant pulse - //voxelInjector->addSample(20000 * sin((i) /((4 / _mouseVoxel.s) * sin((i)/(20 * _mouseVoxel.s / .001))))); //FM 2 comb filter - } - - AudioInjectionManager::threadInjector(voxelInjector); - } } // remember the position for drag detection _justEditedVoxel = true; @@ -4321,10 +4244,10 @@ void Application::nodeKilled(Node* node) { } } -int Application::parseVoxelStats(unsigned char* messageData, ssize_t messageLength, sockaddr senderAddress) { +int Application::parseVoxelStats(unsigned char* messageData, ssize_t messageLength, const HifiSockAddr& senderSockAddr) { // But, also identify the sender, and keep track of the contained jurisdiction root for this server - Node* voxelServer = NodeList::getInstance()->nodeWithAddress(&senderAddress); + Node* voxelServer = NodeList::getInstance()->nodeWithAddress(senderSockAddr); // parse the incoming stats datas stick it in a temporary object for now, while we // determine which server it belongs to @@ -4377,12 +4300,15 @@ void* Application::networkReceive(void* args) { PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::networkReceive()"); - sockaddr senderAddress; + HifiSockAddr senderSockAddr; ssize_t bytesReceived; Application* app = Application::getInstance(); while (!app->_stopNetworkReceiveThread) { - if (NodeList::getInstance()->getNodeSocket()->receive(&senderAddress, app->_incomingPacket, &bytesReceived)) { + if ((bytesReceived = NodeList::getInstance()->getNodeSocket().readDatagram((char*) app->_incomingPacket, + MAX_PACKET_SIZE, + senderSockAddr.getAddressPointer(), + senderSockAddr.getPortPointer()))) { app->_packetCount++; app->_bytesCount += bytesReceived; @@ -4408,11 +4334,11 @@ void* Application::networkReceive(void* args) { "Application::networkReceive()... _voxelProcessor.queueReceivedPacket()"); // add this packet to our list of voxel packets and process them on the voxel processing - app->_voxelProcessor.queueReceivedPacket(senderAddress, app->_incomingPacket, bytesReceived); + app->_voxelProcessor.queueReceivedPacket(senderSockAddr, app->_incomingPacket, bytesReceived); break; } case PACKET_TYPE_BULK_AVATAR_DATA: - NodeList::getInstance()->processBulkNodeData(&senderAddress, + NodeList::getInstance()->processBulkNodeData(senderSockAddr, app->_incomingPacket, bytesReceived); getInstance()->_bandwidthMeter.inputStream(BandwidthMeter::AVATARS).updateValue(bytesReceived); @@ -4430,7 +4356,7 @@ void* Application::networkReceive(void* args) { DataServerClient::processMessageFromDataServer(app->_incomingPacket, bytesReceived); break; default: - NodeList::getInstance()->processNodeData(&senderAddress, app->_incomingPacket, bytesReceived); + NodeList::getInstance()->processNodeData(senderSockAddr, app->_incomingPacket, bytesReceived); break; } } diff --git a/interface/src/Application.h b/interface/src/Application.h index 4695a1bf80..05d981ebd8 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -284,7 +284,6 @@ private: bool maybeEditVoxelUnderCursor(); void deleteVoxelUnderCursor(); void eyedropperVoxelUnderCursor(); - void injectVoxelAddedSoundEffect(); void setMenuShortcutsEnabled(bool enabled); @@ -464,7 +463,7 @@ private: PieMenu _pieMenu; - int parseVoxelStats(unsigned char* messageData, ssize_t messageLength, sockaddr senderAddress); + int parseVoxelStats(unsigned char* messageData, ssize_t messageLength, const HifiSockAddr& senderAddress); NodeToJurisdictionMap _voxelServerJurisdictions; NodeToVoxelSceneStats _voxelServerSceneStats; diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index d3b23f273a..21cbfa21a5 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -19,7 +19,6 @@ #include #include #include -#include #include #include "Application.h" @@ -143,9 +142,9 @@ 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); - nodeList->getNodeSocket()->send(audioMixer->getActiveSocket(), - dataPacket, - BUFFER_LENGTH_BYTES_PER_CHANNEL + leadingBytes); + nodeList->getNodeSocket().writeDatagram((char*) dataPacket, BUFFER_LENGTH_BYTES_PER_CHANNEL + leadingBytes, + audioMixer->getActiveSocket()->getAddress(), + audioMixer->getActiveSocket()->getPort()); interface->getBandwidthMeter()->outputStream(BandwidthMeter::AUDIO).updateValue(BUFFER_LENGTH_BYTES_PER_CHANNEL + leadingBytes); diff --git a/interface/src/DataServerClient.cpp b/interface/src/DataServerClient.cpp index 80be4189b1..547b2dcd3f 100644 --- a/interface/src/DataServerClient.cpp +++ b/interface/src/DataServerClient.cpp @@ -7,10 +7,10 @@ // #include +#include #include #include -#include #include #include "Application.h" @@ -24,7 +24,7 @@ const char MULTI_KEY_VALUE_SEPARATOR = '|'; const char DATA_SERVER_HOSTNAME[] = "data.highfidelity.io"; const unsigned short DATA_SERVER_PORT = 3282; -const sockaddr_in DATA_SERVER_SOCKET = socketForHostnameAndHostOrderPort(DATA_SERVER_HOSTNAME, DATA_SERVER_PORT); +const HifiSockAddr DATA_SERVER_SOCKET = HifiSockAddr(DATA_SERVER_HOSTNAME, DATA_SERVER_PORT); void DataServerClient::putValueForKey(const QString& key, const char* value) { QString clientString = Application::getInstance()->getProfile()->getUserString(); @@ -57,7 +57,8 @@ void DataServerClient::putValueForKey(const QString& key, const char* value) { // _unmatchedPackets.insert(std::pair(putPacket, numPacketBytes)); // send this put request to the data server - NodeList::getInstance()->getNodeSocket()->send((sockaddr*) &DATA_SERVER_SOCKET, putPacket, numPacketBytes); + NodeList::getInstance()->getNodeSocket().writeDatagram((char*) putPacket, numPacketBytes, + DATA_SERVER_SOCKET.getAddress(), DATA_SERVER_SOCKET.getPort()); } } @@ -96,7 +97,8 @@ void DataServerClient::getValuesForKeysAndUserString(const QStringList& keys, co // _unmatchedPackets.insert(std::pair(getPacket, numPacketBytes)); // send the get to the data server - NodeList::getInstance()->getNodeSocket()->send((sockaddr*) &DATA_SERVER_SOCKET, getPacket, numPacketBytes); + NodeList::getInstance()->getNodeSocket().writeDatagram((char*) getPacket, numPacketBytes, + DATA_SERVER_SOCKET.getAddress(), DATA_SERVER_SOCKET.getPort()); } } @@ -236,8 +238,7 @@ void DataServerClient::resendUnmatchedPackets() { mapIterator != _unmatchedPackets.end(); ++mapIterator) { // send the unmatched packet to the data server - NodeList::getInstance()->getNodeSocket()->send((sockaddr*) &DATA_SERVER_SOCKET, - mapIterator->first, - mapIterator->second); + NodeList::getInstance()->getNodeSocket().writeDatagram((char*) mapIterator->first, mapIterator->second, + DATA_SERVER_SOCKET.getAddress(), DATA_SERVER_SOCKET.getPort()); } } diff --git a/interface/src/Environment.cpp b/interface/src/Environment.cpp index 4f4e694713..c82356ba65 100644 --- a/interface/src/Environment.cpp +++ b/interface/src/Environment.cpp @@ -18,24 +18,13 @@ #include "renderer/ProgramObject.h" #include "world.h" -uint qHash(const sockaddr& address) { - const sockaddr_in* inetAddress = reinterpret_cast(&address); - if (inetAddress->sin_family != AF_INET) { +uint qHash(const HifiSockAddr& sockAddr) { + if (sockAddr.getAddress().isNull()) { return 0; // shouldn't happen, but if it does, zero is a perfectly valid hash } - return inetAddress->sin_port + qHash(QByteArray::fromRawData( - reinterpret_cast(&inetAddress->sin_addr), sizeof(in_addr))); -} - -bool operator== (const sockaddr& addr1, const sockaddr& addr2) { - return socketMatch(&addr1, &addr2); -} - -static sockaddr getZeroAddress() { - sockaddr addr; - memset(&addr, 0, sizeof(sockaddr)); - addr.sa_family = AF_INET; - return addr; + quint32 address = sockAddr.getAddress().toIPv4Address(); + return sockAddr.getPort() + qHash(QByteArray::fromRawData((char*) &address, + sizeof(address))); } Environment::Environment() @@ -60,14 +49,14 @@ void Environment::init() { _skyFromSpaceProgram = createSkyProgram("Space", _skyFromSpaceUniformLocations); // start off with a default-constructed environment data - _data[getZeroAddress()][0]; + _data[HifiSockAddr()][0]; _initialized = true; } void Environment::resetToDefault() { _data.clear(); - _data[getZeroAddress()][0]; + _data[HifiSockAddr()][0]; } void Environment::renderAtmospheres(Camera& camera) { @@ -159,7 +148,7 @@ bool Environment::findCapsulePenetration(const glm::vec3& start, const glm::vec3 return found; } -int Environment::parseData(sockaddr *senderAddress, unsigned char* sourceBuffer, int numBytes) { +int Environment::parseData(const HifiSockAddr& senderAddress, unsigned char* sourceBuffer, int numBytes) { // push past the packet header unsigned char* start = sourceBuffer; @@ -175,14 +164,14 @@ int Environment::parseData(sockaddr *senderAddress, unsigned char* sourceBuffer, int dataLength = newData.parseData(sourceBuffer, numBytes); // update the mapping by address/ID - _data[*senderAddress][newData.getID()] = newData; + _data[senderAddress][newData.getID()] = newData; sourceBuffer += dataLength; numBytes -= dataLength; } // remove the default mapping, if any - _data.remove(getZeroAddress()); + _data.remove(HifiSockAddr()); return sourceBuffer - start; } diff --git a/interface/src/Environment.h b/interface/src/Environment.h index 1095687ae0..fc572c5e03 100644 --- a/interface/src/Environment.h +++ b/interface/src/Environment.h @@ -12,7 +12,7 @@ #include #include -#include +#include #include "EnvironmentData.h" #include "InterfaceConfig.h" @@ -34,7 +34,7 @@ public: bool findCapsulePenetration(const glm::vec3& start, const glm::vec3& end, float radius, glm::vec3& penetration); - int parseData(sockaddr *senderAddress, unsigned char* sourceBuffer, int numBytes); + int parseData(const HifiSockAddr& senderSockAddr, unsigned char* sourceBuffer, int numBytes); private: @@ -71,7 +71,7 @@ private: typedef QHash ServerData; - QHash _data; + QHash _data; QMutex _mutex; }; diff --git a/interface/src/PairingHandler.cpp b/interface/src/PairingHandler.cpp index c220c5f943..56d7642640 100644 --- a/interface/src/PairingHandler.cpp +++ b/interface/src/PairingHandler.cpp @@ -10,6 +10,9 @@ #include #include +#include + +#include #include #include "PairingHandler.h" @@ -27,14 +30,14 @@ PairingHandler* PairingHandler::getInstance() { return instance; } -void PairingHandler::sendPairRequest() { - // grab the node socket from the NodeList singleton - UDPSocket *nodeSocket = NodeList::getInstance()->getNodeSocket(); +void PairingHandler::sendPairRequest() { // prepare the pairing request packet + NodeList* nodeList = NodeList::getInstance(); + // use the getLocalAddress helper to get this client's listening address - int localAddress = getLocalAddress(); + quint32 localAddress = getLocalAddress(); char pairPacket[24] = {}; sprintf(pairPacket, "Find %d.%d.%d.%d:%hu", @@ -42,19 +45,13 @@ void PairingHandler::sendPairRequest() { (localAddress >> 8) & 0xFF, (localAddress >> 16) & 0xFF, (localAddress >> 24) & 0xFF, - NodeList::getInstance()->getSocketListenPort()); + NodeList::getInstance()->getNodeSocket().localPort()); qDebug("Sending pair packet: %s\n", pairPacket); - sockaddr_in pairingServerSocket; - - pairingServerSocket.sin_family = AF_INET; - - // lookup the pairing server IP by the hostname - struct hostent* hostInfo = gethostbyname(PAIRING_SERVER_HOSTNAME); - memcpy(&pairingServerSocket.sin_addr, hostInfo->h_addr_list[0], hostInfo->h_length); - pairingServerSocket.sin_port = htons(PAIRING_SERVER_PORT); + HifiSockAddr pairingServerSocket(PAIRING_SERVER_HOSTNAME, PAIRING_SERVER_PORT); // send the pair request to the pairing server - nodeSocket->send((sockaddr*) &pairingServerSocket, pairPacket, strlen(pairPacket)); + nodeList->getNodeSocket().writeDatagram((char*) pairPacket, strlen(pairPacket), + pairingServerSocket.getAddress(), pairingServerSocket.getPort()); } diff --git a/interface/src/VoxelPacketProcessor.cpp b/interface/src/VoxelPacketProcessor.cpp index 9087a5a545..0a76ebe5cb 100644 --- a/interface/src/VoxelPacketProcessor.cpp +++ b/interface/src/VoxelPacketProcessor.cpp @@ -14,7 +14,7 @@ #include "Menu.h" #include "VoxelPacketProcessor.h" -void VoxelPacketProcessor::processPacket(sockaddr& senderAddress, unsigned char* packetData, ssize_t packetLength) { +void VoxelPacketProcessor::processPacket(const HifiSockAddr& senderAddress, unsigned char* packetData, ssize_t packetLength) { PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "VoxelPacketProcessor::processPacket()"); @@ -50,10 +50,10 @@ void VoxelPacketProcessor::processPacket(sockaddr& senderAddress, unsigned char* } // fall through to piggyback message if (Menu::getInstance()->isOptionChecked(MenuOption::Voxels)) { - Node* voxelServer = NodeList::getInstance()->nodeWithAddress(&senderAddress); - if (voxelServer && socketMatch(voxelServer->getActiveSocket(), &senderAddress)) { + Node* voxelServer = NodeList::getInstance()->nodeWithAddress(senderAddress); + if (voxelServer && *voxelServer->getActiveSocket() == senderAddress) { if (packetData[0] == PACKET_TYPE_ENVIRONMENT_DATA) { - app->_environment.parseData(&senderAddress, packetData, messageLength); + app->_environment.parseData(senderAddress, packetData, messageLength); } else { app->_voxels.setDataSourceUUID(voxelServer->getUUID()); app->_voxels.parseData(packetData, messageLength); diff --git a/interface/src/VoxelPacketProcessor.h b/interface/src/VoxelPacketProcessor.h index 87aae397d5..4420ccc6cf 100644 --- a/interface/src/VoxelPacketProcessor.h +++ b/interface/src/VoxelPacketProcessor.h @@ -17,6 +17,6 @@ /// the user is responsible for reading inbound packets and adding them to the processing queue by calling queueReceivedPacket() class VoxelPacketProcessor : public ReceivedPacketProcessor { protected: - virtual void processPacket(sockaddr& senderAddress, unsigned char* packetData, ssize_t packetLength); + virtual void processPacket(const HifiSockAddr& senderAddress, unsigned char* packetData, ssize_t packetLength); }; #endif // __shared__VoxelPacketProcessor__ diff --git a/interface/src/VoxelSystem.h b/interface/src/VoxelSystem.h index d9c672fdf3..7d7a8612d5 100644 --- a/interface/src/VoxelSystem.h +++ b/interface/src/VoxelSystem.h @@ -13,7 +13,6 @@ #include #include -#include #include #include diff --git a/libraries/audio/src/AudioInjectionManager.cpp b/libraries/audio/src/AudioInjectionManager.cpp deleted file mode 100644 index 16ace5bbb6..0000000000 --- a/libraries/audio/src/AudioInjectionManager.cpp +++ /dev/null @@ -1,77 +0,0 @@ -// -// AudioInjectionManager.cpp -// hifi -// -// Created by Stephen Birarda on 5/16/13. -// Copyright (c) 2012 High Fidelity, Inc. All rights reserved. -// - -#include - -#include "SharedUtil.h" -#include "NodeList.h" -#include "NodeTypes.h" -#include "Node.h" -#include "PacketHeaders.h" - -#include "AudioInjectionManager.h" - -UDPSocket* AudioInjectionManager::_injectorSocket = NULL; -sockaddr AudioInjectionManager::_destinationSocket; -bool AudioInjectionManager::_isDestinationSocketExplicit = false; -AudioInjector* AudioInjectionManager::_injectors[50] = {}; - -AudioInjector* AudioInjectionManager::injectorWithCapacity(int capacity) { - for (int i = 0; i < MAX_CONCURRENT_INJECTORS; i++) { - if (!_injectors[i]) { - _injectors[i] = new AudioInjector(capacity); - return _injectors[i]; - } - } - - return NULL; -} - -void AudioInjectionManager::setDestinationSocket(sockaddr& destinationSocket) { - _destinationSocket = destinationSocket; - _isDestinationSocketExplicit = true; -} - -void* AudioInjectionManager::injectAudioViaThread(void* args) { - AudioInjector* injector = (AudioInjector*) args; - - // if we don't have an injectorSocket then grab the one from the node list - if (!_injectorSocket) { - _injectorSocket = NodeList::getInstance()->getNodeSocket(); - } - - // if we don't have an explicit destination socket then pull active socket for current audio mixer from node list - if (!_isDestinationSocketExplicit) { - Node* audioMixer = NodeList::getInstance()->soloNodeOfType(NODE_TYPE_AUDIO_MIXER); - if (audioMixer && audioMixer->getActiveSocket()) { - _destinationSocket = *audioMixer->getActiveSocket(); - } else { - pthread_exit(0); - } - } - - injector->injectAudio(_injectorSocket, &_destinationSocket); - - // if this an injector inside the injection manager's array we're responsible for deletion - for (int i = 0; i < MAX_CONCURRENT_INJECTORS; i++) { - if (_injectors[i] == injector) { - // pointer matched - delete this injector - delete injector; - - // set the pointer to NULL so we can reuse this spot - _injectors[i] = NULL; - } - } - - pthread_exit(0); -} - -void AudioInjectionManager::threadInjector(AudioInjector* injector) { - pthread_t audioInjectThread; - pthread_create(&audioInjectThread, NULL, injectAudioViaThread, (void*) injector); -} \ No newline at end of file diff --git a/libraries/audio/src/AudioInjectionManager.h b/libraries/audio/src/AudioInjectionManager.h deleted file mode 100644 index 5f56663a78..0000000000 --- a/libraries/audio/src/AudioInjectionManager.h +++ /dev/null @@ -1,36 +0,0 @@ -// -// AudioInjectionManager.h -// hifi -// -// Created by Stephen Birarda on 5/16/13. -// Copyright (c) 2012 High Fidelity, Inc. All rights reserved. -// - -#ifndef __hifi__AudioInjectionManager__ -#define __hifi__AudioInjectionManager__ - -#include - -#include "UDPSocket.h" -#include "AudioInjector.h" - -const int MAX_CONCURRENT_INJECTORS = 50; - -class AudioInjectionManager { -public: - static AudioInjector* injectorWithCapacity(int capacity); - - static void threadInjector(AudioInjector* injector); - - static void setInjectorSocket(UDPSocket* injectorSocket) { _injectorSocket = injectorSocket;} - static void setDestinationSocket(sockaddr& destinationSocket); -private: - static void* injectAudioViaThread(void* args); - - static UDPSocket* _injectorSocket; - static sockaddr _destinationSocket; - static bool _isDestinationSocketExplicit; - static AudioInjector* _injectors[MAX_CONCURRENT_INJECTORS]; -}; - -#endif /* defined(__hifi__AudioInjectionManager__) */ diff --git a/libraries/audio/src/AudioInjector.cpp b/libraries/audio/src/AudioInjector.cpp deleted file mode 100644 index 2e58aa13c8..0000000000 --- a/libraries/audio/src/AudioInjector.cpp +++ /dev/null @@ -1,137 +0,0 @@ -// -// AudioInjector.cpp -// hifi -// -// Created by Stephen Birarda on 4/23/13. -// Copyright (c) 2012 High Fidelity, Inc. All rights reserved. -// - -#include -#include -#include - -#include -#include -#include -#include - -#include "AudioInjector.h" - -AudioInjector::AudioInjector(int maxNumSamples) : - _streamIdentifier(QUuid::createUuid()), - _numTotalSamples(maxNumSamples), - _position(0.0f, 0.0f, 0.0f), - _orientation(), - _radius(0.0f), - _volume(MAX_INJECTOR_VOLUME), - _indexOfNextSlot(0), - _isInjectingAudio(false) -{ - _audioSampleArray = new int16_t[maxNumSamples]; - memset(_audioSampleArray, 0, _numTotalSamples * sizeof(int16_t)); -} - -AudioInjector::~AudioInjector() { - delete[] _audioSampleArray; -} - -void AudioInjector::injectAudio(UDPSocket* injectorSocket, sockaddr* destinationSocket) { - if (_audioSampleArray && _indexOfNextSlot > 0) { - _isInjectingAudio = true; - - timeval startTime; - - // calculate the number of bytes required for additional data - int leadingBytes = numBytesForPacketHeader((unsigned char*) &PACKET_TYPE_INJECT_AUDIO) - + NUM_BYTES_RFC4122_UUID - + NUM_BYTES_RFC4122_UUID - + sizeof(_position) - + sizeof(_orientation) - + sizeof(_radius) - + sizeof(_volume); - - unsigned char dataPacket[(BUFFER_LENGTH_SAMPLES_PER_CHANNEL * sizeof(int16_t)) + leadingBytes]; - - unsigned char* currentPacketPtr = dataPacket + populateTypeAndVersion(dataPacket, PACKET_TYPE_INJECT_AUDIO); - - // copy the UUID for the owning node - QByteArray rfcUUID = NodeList::getInstance()->getOwnerUUID().toRfc4122(); - memcpy(currentPacketPtr, rfcUUID.constData(), rfcUUID.size()); - currentPacketPtr += rfcUUID.size(); - - // copy the stream identifier - QByteArray rfcStreamIdentifier = _streamIdentifier.toRfc4122(); - memcpy(currentPacketPtr, rfcStreamIdentifier.constData(), rfcStreamIdentifier.size()); - currentPacketPtr += rfcStreamIdentifier.size(); - - memcpy(currentPacketPtr, &_position, sizeof(_position)); - currentPacketPtr += sizeof(_position); - - memcpy(currentPacketPtr, &_orientation, sizeof(_orientation)); - currentPacketPtr += sizeof(_orientation); - - memcpy(currentPacketPtr, &_radius, sizeof(_radius)); - currentPacketPtr += sizeof(_radius); - - *currentPacketPtr = _volume; - currentPacketPtr++; - - gettimeofday(&startTime, NULL); - int nextFrame = 0; - - for (int i = 0; i < _numTotalSamples; i += BUFFER_LENGTH_SAMPLES_PER_CHANNEL) { - int usecToSleep = usecTimestamp(&startTime) + (nextFrame++ * INJECT_INTERVAL_USECS) - usecTimestampNow(); - if (usecToSleep > 0) { - usleep(usecToSleep); - } - - int numSamplesToCopy = BUFFER_LENGTH_SAMPLES_PER_CHANNEL; - - if (_numTotalSamples - i < BUFFER_LENGTH_SAMPLES_PER_CHANNEL) { - numSamplesToCopy = _numTotalSamples - i; - memset(currentPacketPtr + numSamplesToCopy, - 0, - BUFFER_LENGTH_BYTES_PER_CHANNEL - (numSamplesToCopy * sizeof(int16_t))); - } - - memcpy(currentPacketPtr, _audioSampleArray + i, numSamplesToCopy * sizeof(int16_t)); - - injectorSocket->send(destinationSocket, dataPacket, sizeof(dataPacket)); - } - - _isInjectingAudio = false; - } -} - -void AudioInjector::addSample(const int16_t sample) { - if (_indexOfNextSlot != _numTotalSamples) { - // only add this sample if we actually have space for it - _audioSampleArray[_indexOfNextSlot++] = sample; - } -} - -void AudioInjector::addSamples(int16_t* sampleBuffer, int numSamples) { - if (_audioSampleArray + _indexOfNextSlot + numSamples <= _audioSampleArray + _numTotalSamples) { - // only copy the audio from the sample buffer if there's space - memcpy(_audioSampleArray + _indexOfNextSlot, sampleBuffer, numSamples * sizeof(int16_t)); - _indexOfNextSlot += numSamples; - } -} - -void AudioInjector::clear() { - _indexOfNextSlot = 0; - memset(_audioSampleArray, 0, _numTotalSamples * sizeof(int16_t)); -} - -int16_t& AudioInjector::sampleAt(const int index) { - assert(index >= 0 && index < _numTotalSamples); - - return _audioSampleArray[index]; -} - -void AudioInjector::insertSample(const int index, int sample) { - assert (index >= 0 && index < _numTotalSamples); - - _audioSampleArray[index] = (int16_t) sample; - _indexOfNextSlot = index + 1; -} diff --git a/libraries/audio/src/AudioInjector.h b/libraries/audio/src/AudioInjector.h deleted file mode 100644 index b3a5b82fdf..0000000000 --- a/libraries/audio/src/AudioInjector.h +++ /dev/null @@ -1,73 +0,0 @@ -// -// AudioInjector.h -// hifi -// -// Created by Stephen Birarda on 4/23/13. -// Copyright (c) 2012 High Fidelity, Inc. All rights reserved. -// - -#ifndef __hifi__AudioInjector__ -#define __hifi__AudioInjector__ - -#include -#include - -#include -#include - -#include -#include - -#include "AudioRingBuffer.h" - -const int MAX_INJECTOR_VOLUME = 0xFF; - -const int INJECT_INTERVAL_USECS = floorf((BUFFER_LENGTH_SAMPLES_PER_CHANNEL / SAMPLE_RATE) * 1000000); - -class AudioInjector : public QObject { - Q_OBJECT - - Q_PROPERTY(glm::vec3 position READ getPosition WRITE setPosition) - Q_PROPERTY(uchar volume READ getVolume WRITE setVolume); -public: - AudioInjector(int maxNumSamples); - ~AudioInjector(); - - void injectAudio(UDPSocket* injectorSocket, sockaddr* destinationSocket); - - bool isInjectingAudio() const { return _isInjectingAudio; } - - unsigned char getVolume() const { return _volume; } - void setVolume(unsigned char volume) { _volume = volume; } - - const glm::vec3& getPosition() const { return _position; } - void setPosition(const glm::vec3& position) { _position = position; } - - const glm::quat& getOrientation() const { return _orientation; } - void setOrientation(const glm::quat& orientation) { _orientation = orientation; } - - float getRadius() const { return _radius; } - void setRadius(float radius) { _radius = radius; } - - bool hasSamplesToInject() const { return _indexOfNextSlot > 0; } - - void addSample(const int16_t sample); - void addSamples(int16_t* sampleBuffer, int numSamples); - - void clear(); -public slots: - int16_t& sampleAt(const int index); - void insertSample(const int index, int sample); -private: - QUuid _streamIdentifier; - int16_t* _audioSampleArray; - int _numTotalSamples; - glm::vec3 _position; - glm::quat _orientation; - float _radius; - unsigned char _volume; - int _indexOfNextSlot; - bool _isInjectingAudio; -}; - -#endif /* defined(__hifi__AudioInjector__) */ diff --git a/libraries/audio/src/InjectedAudioRingBuffer.cpp b/libraries/audio/src/InjectedAudioRingBuffer.cpp index 18ee037ea9..9adb525b93 100644 --- a/libraries/audio/src/InjectedAudioRingBuffer.cpp +++ b/libraries/audio/src/InjectedAudioRingBuffer.cpp @@ -24,6 +24,8 @@ InjectedAudioRingBuffer::InjectedAudioRingBuffer(const QUuid& streamIdentifier) } +const uchar MAX_INJECTOR_VOLUME = 255; + int InjectedAudioRingBuffer::parseData(unsigned char* sourceBuffer, int numBytes) { unsigned char* currentBuffer = sourceBuffer + numBytesForPacketHeader(sourceBuffer); diff --git a/libraries/audio/src/InjectedAudioRingBuffer.h b/libraries/audio/src/InjectedAudioRingBuffer.h index bab540919d..b5845366fb 100644 --- a/libraries/audio/src/InjectedAudioRingBuffer.h +++ b/libraries/audio/src/InjectedAudioRingBuffer.h @@ -11,8 +11,6 @@ #include -#include "AudioInjector.h" - #include "PositionalAudioRingBuffer.h" class InjectedAudioRingBuffer : public PositionalAudioRingBuffer { diff --git a/libraries/shared/src/HifiSockAddr.cpp b/libraries/shared/src/HifiSockAddr.cpp new file mode 100644 index 0000000000..542b4c2e52 --- /dev/null +++ b/libraries/shared/src/HifiSockAddr.cpp @@ -0,0 +1,110 @@ +// +// HifiSockAddr.cpp +// hifi +// +// Created by Stephen Birarda on 11/26/2013. +// Copyright (c) 2013 HighFidelity, Inc. All rights reserved. +// + +#include "HifiSockAddr.h" + +#include +#include + +HifiSockAddr::HifiSockAddr() : + _address(QHostAddress::Null), + _port(0) +{ + +} + +HifiSockAddr::HifiSockAddr(const QHostAddress& address, quint16 port) : + _address(address), + _port(port) +{ + +} + +HifiSockAddr::HifiSockAddr(const HifiSockAddr& otherSockAddr) { + _address = otherSockAddr._address; + _port = otherSockAddr._port; +} + +HifiSockAddr::HifiSockAddr(const QString& hostname, quint16 hostOrderPort) { + // lookup the IP by the hostname + QHostInfo hostInfo = QHostInfo::fromName(hostname); + if (!hostInfo.addresses().isEmpty()) { + // use the first IP address + _address = hostInfo.addresses().first(); + _port = hostOrderPort; } +} + +HifiSockAddr& HifiSockAddr::operator=(const HifiSockAddr& rhsSockAddr) { + HifiSockAddr temp(rhsSockAddr); + swap(temp); + return *this; +} + +void HifiSockAddr::swap(HifiSockAddr& otherSockAddr) { + using std::swap; + + swap(_address, otherSockAddr._address); + swap(_port, otherSockAddr._port); +} + +int HifiSockAddr::packSockAddr(unsigned char* packetData, const HifiSockAddr& packSockAddr) { + unsigned int addressToPack = packSockAddr._address.toIPv4Address(); + memcpy(packetData, &addressToPack, sizeof(packSockAddr._address.toIPv4Address())); + memcpy(packetData, &packSockAddr._port, sizeof(packSockAddr._port)); + + return sizeof(addressToPack) + sizeof(packSockAddr._port); +} + +int HifiSockAddr::unpackSockAddr(const unsigned char* packetData, HifiSockAddr& unpackDestSockAddr) { + unpackDestSockAddr._address = QHostAddress(*((quint32*) packetData)); + unpackDestSockAddr._port = *((quint16*) (packetData + sizeof(quint32))); + + return sizeof(quint32) + sizeof(quint16); +} + +bool HifiSockAddr::operator==(const HifiSockAddr &rhsSockAddr) const { + return _address == rhsSockAddr._address && _port == rhsSockAddr._port; +} + +QDebug operator<<(QDebug debug, const HifiSockAddr &hifiSockAddr) { + debug.nospace() << hifiSockAddr._address.toString() << ":" << hifiSockAddr._port; + return debug; +} + +quint32 getLocalAddress() { + + static int localAddress = 0; + + if (localAddress == 0) { + foreach(const QNetworkInterface &interface, QNetworkInterface::allInterfaces()) { + if (interface.flags() & QNetworkInterface::IsUp + && interface.flags() & QNetworkInterface::IsRunning + && interface.flags() & ~QNetworkInterface::IsLoopBack) { + // we've decided that this is the active NIC + // enumerate it's addresses to grab the IPv4 address + foreach(const QNetworkAddressEntry &entry, interface.addressEntries()) { + // make sure it's an IPv4 address that isn't the loopback + if (entry.ip().protocol() == QAbstractSocket::IPv4Protocol && !entry.ip().isLoopback()) { + qDebug("Node's local address is %s\n", entry.ip().toString().toLocal8Bit().constData()); + + // set our localAddress and break out + localAddress = htonl(entry.ip().toIPv4Address()); + break; + } + } + } + + if (localAddress != 0) { + break; + } + } + } + + // return the looked up local address + return localAddress; +} diff --git a/libraries/shared/src/HifiSockAddr.h b/libraries/shared/src/HifiSockAddr.h new file mode 100644 index 0000000000..c5a20896e7 --- /dev/null +++ b/libraries/shared/src/HifiSockAddr.h @@ -0,0 +1,48 @@ +// +// HifiSockAddr.h +// hifi +// +// Created by Stephen Birarda on 11/26/2013. +// Copyright (c) 2013 HighFidelity, Inc. All rights reserved. +// + +#ifndef __hifi__HifiSockAddr__ +#define __hifi__HifiSockAddr__ + +#include + +class HifiSockAddr { +public: + HifiSockAddr(); + HifiSockAddr(const QHostAddress& address, quint16 port); + HifiSockAddr(const HifiSockAddr& otherSockAddr); + HifiSockAddr(const QString& hostname, quint16 hostOrderPort); + + bool isNull() const { return _address.isNull() && _port == 0; } + + HifiSockAddr& operator=(const HifiSockAddr& rhsSockAddr); + void swap(HifiSockAddr& otherSockAddr); + + bool operator==(const HifiSockAddr& rhsSockAddr) const; + bool operator!=(const HifiSockAddr& rhsSockAddr) const { return !(*this == rhsSockAddr); } + + const QHostAddress& getAddress() const { return _address; } + QHostAddress* getAddressPointer() { return &_address; } + void setAddress(const QHostAddress& address) { _address = address; } + + quint16 getPort() const { return _port; } + quint16* getPortPointer() { return &_port; } + void setPort(quint16 port) { _port = port; } + + static int packSockAddr(unsigned char* packetData, const HifiSockAddr& packSockAddr); + static int unpackSockAddr(const unsigned char* packetData, HifiSockAddr& unpackDestSockAddr); + + friend QDebug operator<<(QDebug debug, const HifiSockAddr &hifiSockAddr); +private: + QHostAddress _address; + quint16 _port; +}; + +quint32 getLocalAddress(); + +#endif /* defined(__hifi__HifiSockAddr__) */ diff --git a/libraries/shared/src/Logging.cpp b/libraries/shared/src/Logging.cpp index 0182034be6..866d603861 100644 --- a/libraries/shared/src/Logging.cpp +++ b/libraries/shared/src/Logging.cpp @@ -11,35 +11,35 @@ #include #include +#include + +#include "HifiSockAddr.h" #include "SharedUtil.h" #include "NodeList.h" #include "Logging.h" -sockaddr_in Logging::logstashSocket = {}; +HifiSockAddr Logging::logstashSocket = HifiSockAddr(); char* Logging::targetName = NULL; -sockaddr* Logging::socket() { +const HifiSockAddr& Logging::socket() { - if (logstashSocket.sin_addr.s_addr == 0) { + if (logstashSocket.getAddress().isNull()) { // we need to construct the socket object - - // assume IPv4 - logstashSocket.sin_family = AF_INET; - // use the constant port - logstashSocket.sin_port = htons(LOGSTASH_UDP_PORT); + logstashSocket.setPort(htons(LOGSTASH_UDP_PORT)); // lookup the IP address for the constant hostname - struct hostent* logstashHostInfo; - if ((logstashHostInfo = gethostbyname(LOGSTASH_HOSTNAME))) { - memcpy(&logstashSocket.sin_addr, logstashHostInfo->h_addr_list[0], logstashHostInfo->h_length); + QHostInfo hostInfo = QHostInfo::fromName(LOGSTASH_HOSTNAME); + if (!hostInfo.addresses().isEmpty()) { + // use the first IP address + logstashSocket.setAddress(hostInfo.addresses().first()); } else { printf("Failed to lookup logstash IP - will try again on next log attempt.\n"); } } - return (sockaddr*) &logstashSocket; + return logstashSocket; } bool Logging::shouldSendStats() { @@ -57,7 +57,8 @@ void Logging::stashValue(char statType, const char* key, float value) { NodeList *nodeList = NodeList::getInstance(); if (nodeList) { - nodeList->getNodeSocket()->send(socket(), logstashPacket, numPacketBytes); + nodeList->getNodeSocket().writeDatagram(logstashPacket, numPacketBytes, + logstashSocket.getAddress(), logstashSocket.getPort()); } } diff --git a/libraries/shared/src/Logging.h b/libraries/shared/src/Logging.h index c4f921070a..d64c39992b 100644 --- a/libraries/shared/src/Logging.h +++ b/libraries/shared/src/Logging.h @@ -20,11 +20,13 @@ const char STAT_TYPE_TIMER = 't'; const char STAT_TYPE_COUNTER = 'c'; const char STAT_TYPE_GAUGE = 'g'; +class HifiSockAddr; + /// Handles custom message handling and sending of stats/logs to Logstash instance class Logging { public: /// \return the socket used to send stats to logstash - static sockaddr* socket(); + static const HifiSockAddr& socket(); /// checks if this target should send stats to logstash, given its current environment /// \return true if the caller should send stats to logstash @@ -44,7 +46,7 @@ public: /// prints various process, message type, and time information static void verboseMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString &message); private: - static sockaddr_in logstashSocket; + static HifiSockAddr logstashSocket; static char* targetName; }; diff --git a/libraries/shared/src/NetworkPacket.cpp b/libraries/shared/src/NetworkPacket.cpp index 0acabbac58..575e80b59b 100644 --- a/libraries/shared/src/NetworkPacket.cpp +++ b/libraries/shared/src/NetworkPacket.cpp @@ -22,10 +22,10 @@ NetworkPacket::~NetworkPacket() { // nothing to do } -void NetworkPacket::copyContents(const sockaddr& address, const unsigned char* packetData, ssize_t packetLength) { +void NetworkPacket::copyContents(const HifiSockAddr& sockAddr, const unsigned char* packetData, ssize_t packetLength) { _packetLength = 0; if (packetLength >=0 && packetLength <= MAX_PACKET_SIZE) { - memcpy(&_address, &address, sizeof(_address)); + _sockAddr = sockAddr; _packetLength = packetLength; memcpy(&_packetData[0], packetData, packetLength); } else { @@ -34,16 +34,16 @@ void NetworkPacket::copyContents(const sockaddr& address, const unsigned char* } NetworkPacket::NetworkPacket(const NetworkPacket& packet) { - copyContents(packet.getAddress(), packet.getData(), packet.getLength()); + copyContents(packet.getSockAddr(), packet.getData(), packet.getLength()); } -NetworkPacket::NetworkPacket(sockaddr& address, unsigned char* packetData, ssize_t packetLength) { - copyContents(address, packetData, packetLength); +NetworkPacket::NetworkPacket(const HifiSockAddr& sockAddr, unsigned char* packetData, ssize_t packetLength) { + copyContents(sockAddr, packetData, packetLength); }; // copy assignment NetworkPacket& NetworkPacket::operator=(NetworkPacket const& other) { - copyContents(other.getAddress(), other.getData(), other.getLength()); + copyContents(other.getSockAddr(), other.getData(), other.getLength()); return *this; } diff --git a/libraries/shared/src/NetworkPacket.h b/libraries/shared/src/NetworkPacket.h index 9c7c61e10f..b30564087d 100644 --- a/libraries/shared/src/NetworkPacket.h +++ b/libraries/shared/src/NetworkPacket.h @@ -15,6 +15,8 @@ #include #include +#include "HifiSockAddr.h" + #include "NodeList.h" // for MAX_PACKET_SIZE /// Storage of not-yet processed inbound, or not yet sent outbound generic UDP network packet @@ -30,19 +32,19 @@ public: NetworkPacket& operator= (NetworkPacket&& other); // move assignment #endif - NetworkPacket(sockaddr& address, unsigned char* packetData, ssize_t packetLength); + NetworkPacket(const HifiSockAddr& sockAddr, unsigned char* packetData, ssize_t packetLength); - sockaddr& getAddress() { return _address; } + const HifiSockAddr& getSockAddr() const { return _sockAddr; } ssize_t getLength() const { return _packetLength; } unsigned char* getData() { return &_packetData[0]; } - const sockaddr& getAddress() const { return _address; } + const HifiSockAddr& getAddress() const { return _sockAddr; } const unsigned char* getData() const { return &_packetData[0]; } private: - void copyContents(const sockaddr& address, const unsigned char* packetData, ssize_t packetLength); + void copyContents(const HifiSockAddr& sockAddr, const unsigned char* packetData, ssize_t packetLength); - sockaddr _address; + HifiSockAddr _sockAddr; ssize_t _packetLength; unsigned char _packetData[MAX_PACKET_SIZE]; }; diff --git a/libraries/shared/src/Node.cpp b/libraries/shared/src/Node.cpp index d4bd8a084a..cc82677f9a 100644 --- a/libraries/shared/src/Node.cpp +++ b/libraries/shared/src/Node.cpp @@ -19,30 +19,25 @@ #include "Node.h" #include "NodeTypes.h" #include "SharedUtil.h" -#include "UDPSocket.h" #include -Node::Node(const QUuid& uuid, char type, sockaddr* publicSocket, sockaddr* localSocket) : +Node::Node(const QUuid& uuid, char type, const HifiSockAddr& publicSocket, const HifiSockAddr& localSocket) : _type(type), _uuid(uuid), _wakeMicrostamp(usecTimestampNow()), _lastHeardMicrostamp(usecTimestampNow()), + _publicSocket(publicSocket), + _localSocket(localSocket), _activeSocket(NULL), _bytesReceivedMovingAverage(NULL), _linkedData(NULL), _isAlive(true) { - setPublicSocket(publicSocket); - setLocalSocket(localSocket); - pthread_mutex_init(&_mutex, 0); } Node::~Node() { - delete _publicSocket; - delete _localSocket; - if (_linkedData) { _linkedData->deleteOrDeleteLater(); } @@ -86,47 +81,32 @@ const char* Node::getTypeName() const { } } -void Node::setPublicSocket(sockaddr* publicSocket) { - if (_activeSocket == _publicSocket) { +void Node::setPublicSocket(const HifiSockAddr& publicSocket) { + if (_activeSocket == &_publicSocket) { // if the active socket was the public socket then reset it to NULL _activeSocket = NULL; } - if (publicSocket) { - _publicSocket = new sockaddr(*publicSocket); - } else { - _publicSocket = NULL; - } + _publicSocket = publicSocket; } -void Node::setLocalSocket(sockaddr* localSocket) { - if (_activeSocket == _localSocket) { +void Node::setLocalSocket(const HifiSockAddr& localSocket) { + if (_activeSocket == &_localSocket) { // if the active socket was the local socket then reset it to NULL _activeSocket = NULL; } - if (localSocket) { - _localSocket = new sockaddr(*localSocket); - } else { - _localSocket = NULL; - } + _localSocket = localSocket; } void Node::activateLocalSocket() { qDebug() << "Activating local socket for node" << *this << "\n"; - _activeSocket = _localSocket; + _activeSocket = &_localSocket; } void Node::activatePublicSocket() { qDebug() << "Activating public socket for node" << *this << "\n"; - _activeSocket = _publicSocket; -} - -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); + _activeSocket = &_publicSocket; } void Node::recordBytesReceived(int bytesReceived) { @@ -154,15 +134,8 @@ float Node::getAverageKilobitsPerSecond() { } QDebug operator<<(QDebug debug, const Node &node) { - char publicAddressBuffer[16] = {'\0'}; - unsigned short publicAddressPort = loadBufferWithSocketInfo(publicAddressBuffer, node.getPublicSocket()); - - char localAddressBuffer[16] = {'\0'}; - unsigned short localAddressPort = loadBufferWithSocketInfo(localAddressBuffer, node.getLocalSocket()); - debug.nospace() << node.getTypeName() << " (" << node.getType() << ")"; debug << " " << node.getUUID().toString().toLocal8Bit().constData() << " "; - debug.nospace() << publicAddressBuffer << ":" << publicAddressPort; - debug.nospace() << " / " << localAddressBuffer << ":" << localAddressPort; + debug.nospace() << node.getLocalSocket() << "/" << node.getPublicSocket(); return debug.nospace(); } diff --git a/libraries/shared/src/Node.h b/libraries/shared/src/Node.h index 3f7780d63d..4614a6f0a8 100644 --- a/libraries/shared/src/Node.h +++ b/libraries/shared/src/Node.h @@ -21,19 +21,18 @@ #include #include +#include "HifiSockAddr.h" #include "NodeData.h" #include "SimpleMovingAverage.h" class Node { public: - Node(const QUuid& uuid, char type, sockaddr* publicSocket, sockaddr* localSocket); + Node(const QUuid& uuid, char type, const HifiSockAddr& publicSocket, const HifiSockAddr& localSocket); ~Node(); bool operator==(const Node& otherNode) const { return _uuid == otherNode._uuid; } bool operator!=(const Node& otherNode) const { return !(*this == otherNode); } - bool matches(sockaddr* otherPublicSocket, sockaddr* otherLocalSocket, char otherNodeType); - char getType() const { return _type; } void setType(char type) { _type = type; } const char* getTypeName() const; @@ -47,12 +46,12 @@ public: uint64_t getLastHeardMicrostamp() const { return _lastHeardMicrostamp; } void setLastHeardMicrostamp(uint64_t lastHeardMicrostamp) { _lastHeardMicrostamp = lastHeardMicrostamp; } - sockaddr* getPublicSocket() const { return _publicSocket; } - void setPublicSocket(sockaddr* publicSocket); - sockaddr* getLocalSocket() const { return _localSocket; } - void setLocalSocket(sockaddr* localSocket); + const HifiSockAddr& getPublicSocket() const { return _publicSocket; } + void setPublicSocket(const HifiSockAddr& publicSocket); + const HifiSockAddr& getLocalSocket() const { return _localSocket; } + void setLocalSocket(const HifiSockAddr& localSocket); - sockaddr* getActiveSocket() const { return _activeSocket; } + const HifiSockAddr* getActiveSocket() const { return _activeSocket; } void activatePublicSocket(); void activateLocalSocket(); @@ -87,9 +86,9 @@ private: QUuid _uuid; uint64_t _wakeMicrostamp; uint64_t _lastHeardMicrostamp; - sockaddr* _publicSocket; - sockaddr* _localSocket; - sockaddr* _activeSocket; + HifiSockAddr _publicSocket; + HifiSockAddr _localSocket; + HifiSockAddr* _activeSocket; SimpleMovingAverage* _bytesReceivedMovingAverage; NodeData* _linkedData; bool _isAlive; diff --git a/libraries/shared/src/NodeList.cpp b/libraries/shared/src/NodeList.cpp index daa0d7a4b1..59135b05d4 100644 --- a/libraries/shared/src/NodeList.cpp +++ b/libraries/shared/src/NodeList.cpp @@ -15,6 +15,7 @@ #include #include "Assignment.h" +#include "HifiSockAddr.h" #include "Logging.h" #include "NodeList.h" #include "NodeTypes.h" @@ -61,22 +62,20 @@ NodeList* NodeList::getInstance() { NodeList::NodeList(char newOwnerType, unsigned short int newSocketListenPort) : _domainHostname(DEFAULT_DOMAIN_HOSTNAME), - _domainIP(), - _domainPort(DEFAULT_DOMAIN_SERVER_PORT), + _domainSockAddr(HifiSockAddr(QHostAddress::Null, DEFAULT_DOMAIN_SERVER_PORT)), _nodeBuckets(), _numNodes(0), - _nodeSocket(newSocketListenPort), + _nodeSocket(), _ownerType(newOwnerType), _nodeTypesOfInterest(NULL), _ownerUUID(QUuid::createUuid()), _numNoReplyDomainCheckIns(0), - _assignmentServerSocket(NULL), - _publicAddress(), - _publicPort(0), + _assignmentServerSocket(), + _publicSockAddr(), _hasCompletedInitialSTUNFailure(false), _stunRequestsSinceSuccess(0) { - + _nodeSocket.bind(QHostAddress::LocalHost, newSocketListenPort); } NodeList::~NodeList() { @@ -100,29 +99,29 @@ void NodeList::setDomainHostname(const QString& domainHostname) { _domainHostname = domainHostname.left(colonIndex); // grab the port by reading the string after the colon - _domainPort = atoi(domainHostname.mid(colonIndex + 1, domainHostname.size()).toLocal8Bit().constData()); + _domainSockAddr.setPort(atoi(domainHostname.mid(colonIndex + 1, domainHostname.size()).toLocal8Bit().constData())); - qDebug() << "Updated hostname to" << _domainHostname << "and port to" << _domainPort << "\n"; + qDebug() << "Updated hostname to" << _domainHostname << "and port to" << _domainSockAddr.getPort() << "\n"; } else { // no port included with the hostname, simply set the member variable and reset the domain server port to default _domainHostname = domainHostname; - _domainPort = DEFAULT_DOMAIN_SERVER_PORT; + _domainSockAddr.setPort(DEFAULT_DOMAIN_SERVER_PORT); } // clear the NodeList so nodes from this domain are killed clear(); // reset our _domainIP to the null address so that a lookup happens on next check in - _domainIP.clear(); + _domainSockAddr.setAddress(QHostAddress::Null); notifyDomainChanged(); } } -void NodeList::timePingReply(sockaddr *nodeAddress, unsigned char *packetData) { +void NodeList::timePingReply(const HifiSockAddr& nodeAddress, unsigned char *packetData) { for(NodeList::iterator node = begin(); node != end(); node++) { - if (socketMatch(node->getPublicSocket(), nodeAddress) || - socketMatch(node->getLocalSocket(), nodeAddress)) { + if (node->getPublicSocket() == nodeAddress || + node->getLocalSocket() == nodeAddress) { int pingTime = usecTimestampNow() - *(uint64_t*)(packetData + numBytesForPacketHeader(packetData)); @@ -132,11 +131,11 @@ void NodeList::timePingReply(sockaddr *nodeAddress, unsigned char *packetData) { } } -void NodeList::processNodeData(sockaddr* senderAddress, unsigned char* packetData, size_t dataBytes) { +void NodeList::processNodeData(const HifiSockAddr& senderSockAddr, unsigned char* packetData, size_t dataBytes) { switch (packetData[0]) { case PACKET_TYPE_DOMAIN: { // only process the DS if this is our current domain server - if (_domainIP == QHostAddress(senderAddress)) { + if (_domainSockAddr == senderSockAddr) { processDomainServerList(packetData, dataBytes); } @@ -145,15 +144,15 @@ void NodeList::processNodeData(sockaddr* senderAddress, unsigned char* packetDat case PACKET_TYPE_PING: { // send it right back populateTypeAndVersion(packetData, PACKET_TYPE_PING_REPLY); - _nodeSocket.send(senderAddress, packetData, dataBytes); + _nodeSocket.writeDatagram((char*) packetData, dataBytes, senderSockAddr.getAddress(), senderSockAddr.getPort()); break; } case PACKET_TYPE_PING_REPLY: { // activate the appropriate socket for this node, if not yet updated - activateSocketFromNodeCommunication(senderAddress); + activateSocketFromNodeCommunication(senderSockAddr); // set the ping time for this node for stat collection - timePingReply(senderAddress, packetData); + timePingReply(senderSockAddr, packetData); break; } case PACKET_TYPE_STUN_RESPONSE: { @@ -169,7 +168,7 @@ void NodeList::processNodeData(sockaddr* senderAddress, unsigned char* packetDat } } -void NodeList::processBulkNodeData(sockaddr *senderAddress, unsigned char *packetData, int numTotalBytes) { +void NodeList::processBulkNodeData(const HifiSockAddr& senderAddress, unsigned char *packetData, int numTotalBytes) { // find the avatar mixer in our node list and update the lastRecvTime from it Node* bulkSendNode = nodeWithAddress(senderAddress); @@ -198,11 +197,11 @@ void NodeList::processBulkNodeData(sockaddr *senderAddress, unsigned char *packe if (!matchingNode) { // we're missing this node, we need to add it to the list - matchingNode = addOrUpdateNode(nodeUUID, NODE_TYPE_AGENT, NULL, NULL); + matchingNode = addOrUpdateNode(nodeUUID, NODE_TYPE_AGENT, HifiSockAddr(), HifiSockAddr()); } currentPosition += updateNodeWithData(matchingNode, - NULL, + HifiSockAddr(), packetHolder, numTotalBytes - (currentPosition - startPosition)); @@ -210,16 +209,16 @@ void NodeList::processBulkNodeData(sockaddr *senderAddress, unsigned char *packe } } -int NodeList::updateNodeWithData(Node *node, sockaddr* senderAddress, unsigned char *packetData, int dataBytes) { +int NodeList::updateNodeWithData(Node *node, const HifiSockAddr& senderSockAddr, unsigned char *packetData, int dataBytes) { node->lock(); node->setLastHeardMicrostamp(usecTimestampNow()); - if (senderAddress) { - activateSocketFromNodeCommunication(senderAddress); + if (!senderSockAddr.isNull()) { + activateSocketFromNodeCommunication(senderSockAddr); } - if (node->getActiveSocket() || !senderAddress) { + if (node->getActiveSocket() || senderSockAddr.isNull()) { node->recordBytesReceived(dataBytes); if (!node->getLinkedData() && linkedDataCreateCallback) { @@ -238,9 +237,9 @@ int NodeList::updateNodeWithData(Node *node, sockaddr* senderAddress, unsigned c } } -Node* NodeList::nodeWithAddress(sockaddr *senderAddress) { +Node* NodeList::nodeWithAddress(const HifiSockAddr &senderSockAddr) { for(NodeList::iterator node = begin(); node != end(); node++) { - if (node->getActiveSocket() && socketMatch(node->getActiveSocket(), senderAddress)) { + if (node->getActiveSocket() && *node->getActiveSocket() == senderSockAddr) { return &(*node); } } @@ -350,10 +349,8 @@ void NodeList::sendSTUNRequest() { qDebug("Sending intial stun request to %s\n", stunIPAddress.toLocal8Bit().constData()); } - _nodeSocket.send(stunIPAddress.toLocal8Bit().constData(), - STUN_SERVER_PORT, - stunRequestPacket, - sizeof(stunRequestPacket)); + _nodeSocket.writeDatagram((char*) stunRequestPacket, sizeof(stunRequestPacket), + QHostAddress(stunIPAddress), STUN_SERVER_PORT); break; } @@ -372,8 +369,7 @@ void NodeList::sendSTUNRequest() { } // reset the public address and port - _publicAddress = QHostAddress::Null; - _publicPort = 0; + _publicSockAddr = HifiSockAddr(); } } @@ -425,13 +421,12 @@ void NodeList::processSTUNResponse(unsigned char* packetData, size_t dataBytes) QHostAddress newPublicAddress = QHostAddress(stunAddress); - if (newPublicAddress != _publicAddress || newPublicPort != _publicPort) { - _publicAddress = newPublicAddress; - _publicPort = newPublicPort; + if (newPublicAddress != _publicSockAddr.getAddress() || newPublicPort != _publicSockAddr.getPort()) { + _publicSockAddr = HifiSockAddr(newPublicAddress, newPublicPort); qDebug("New public socket received from STUN server is %s:%hu\n", - _publicAddress.toString().toLocal8Bit().constData(), - _publicPort); + _publicSockAddr.getAddress().toString().toLocal8Bit().constData(), + _publicSockAddr.getPort()); } @@ -489,17 +484,17 @@ void NodeList::sendDomainServerCheckIn() { static bool printedDomainServerIP = false; // Lookup the IP address of the domain server if we need to - if (_domainIP.isNull()) { + if (_domainSockAddr.getAddress().isNull()) { qDebug("Looking up DS hostname %s.\n", _domainHostname.toLocal8Bit().constData()); QHostInfo domainServerHostInfo = QHostInfo::fromName(_domainHostname); for (int i = 0; i < domainServerHostInfo.addresses().size(); i++) { if (domainServerHostInfo.addresses()[i].protocol() == QAbstractSocket::IPv4Protocol) { - _domainIP = domainServerHostInfo.addresses()[i]; + _domainSockAddr.setAddress(domainServerHostInfo.addresses()[i]); qDebug("DS at %s is at %s\n", _domainHostname.toLocal8Bit().constData(), - _domainIP.toString().toLocal8Bit().constData()); + _domainSockAddr.getAddress().toString().toLocal8Bit().constData()); printedDomainServerIP = true; @@ -512,11 +507,11 @@ void NodeList::sendDomainServerCheckIn() { } } } else if (!printedDomainServerIP) { - qDebug("Domain Server IP: %s\n", _domainIP.toString().toLocal8Bit().constData()); + qDebug("Domain Server IP: %s\n", _domainSockAddr.getAddress().toString().toLocal8Bit().constData()); printedDomainServerIP = true; } - if (_publicAddress.isNull() && !_hasCompletedInitialSTUNFailure) { + if (_publicSockAddr.isNull() && !_hasCompletedInitialSTUNFailure) { // we don't know our public socket and we need to send it to the domain server // send a STUN request to figure it out sendSTUNRequest(); @@ -548,13 +543,11 @@ void NodeList::sendDomainServerCheckIn() { packetPosition += rfcOwnerUUID.size(); // pack our public address to send to domain-server - packetPosition += packSocket(checkInPacket + (packetPosition - checkInPacket), - htonl(_publicAddress.toIPv4Address()), htons(_publicPort)); + packetPosition += HifiSockAddr::packSockAddr(checkInPacket + (packetPosition - checkInPacket), _publicSockAddr); // pack our local address to send to domain-server - packetPosition += packSocket(checkInPacket + (packetPosition - checkInPacket), - getLocalAddress(), - htons(_nodeSocket.getListeningPort())); + packetPosition += HifiSockAddr::packSockAddr(checkInPacket + (packetPosition - checkInPacket), + HifiSockAddr(_nodeSocket.localAddress(), _nodeSocket.localPort())); // add the number of bytes for node types of interest *(packetPosition++) = numBytesNodesOfInterest; @@ -567,9 +560,8 @@ void NodeList::sendDomainServerCheckIn() { packetPosition += numBytesNodesOfInterest; } - _nodeSocket.send(_domainIP.toString().toLocal8Bit().constData(), _domainPort, checkInPacket, - packetPosition - checkInPacket); - + _nodeSocket.writeDatagram((char*) checkInPacket, packetPosition - checkInPacket, + _domainSockAddr.getAddress(), _domainSockAddr.getPort()); const int NUM_DOMAIN_SERVER_CHECKINS_PER_STUN_REQUEST = 5; static unsigned int numDomainCheckins = 0; @@ -592,10 +584,8 @@ int NodeList::processDomainServerList(unsigned char* packetData, size_t dataByte char nodeType; // assumes only IPv4 addresses - sockaddr_in nodePublicSocket; - nodePublicSocket.sin_family = AF_INET; - sockaddr_in nodeLocalSocket; - nodeLocalSocket.sin_family = AF_INET; + HifiSockAddr nodePublicSocket; + HifiSockAddr nodeLocalSocket; unsigned char* readPtr = packetData + numBytesForPacketHeader(packetData); unsigned char* startPtr = packetData; @@ -605,24 +595,24 @@ int NodeList::processDomainServerList(unsigned char* packetData, size_t dataByte QUuid nodeUUID = QUuid::fromRfc4122(QByteArray((char*) readPtr, NUM_BYTES_RFC4122_UUID)); readPtr += NUM_BYTES_RFC4122_UUID; - readPtr += unpackSocket(readPtr, (sockaddr*) &nodePublicSocket); - readPtr += unpackSocket(readPtr, (sockaddr*) &nodeLocalSocket); + readPtr += HifiSockAddr::unpackSockAddr(readPtr, nodePublicSocket); + readPtr += HifiSockAddr::unpackSockAddr(readPtr, nodeLocalSocket); // if the public socket address is 0 then it's reachable at the same IP // as the domain server - if (nodePublicSocket.sin_addr.s_addr == 0) { - nodePublicSocket.sin_addr.s_addr = htonl(_domainIP.toIPv4Address()); + if (nodePublicSocket.getAddress().isNull()) { + nodePublicSocket.setAddress(_domainSockAddr.getAddress()); } - addOrUpdateNode(nodeUUID, nodeType, (sockaddr*) &nodePublicSocket, (sockaddr*) &nodeLocalSocket); + addOrUpdateNode(nodeUUID, nodeType, nodePublicSocket, nodeLocalSocket); } return readNodes; } -const sockaddr_in DEFAULT_LOCAL_ASSIGNMENT_SOCKET = socketForHostnameAndHostOrderPort(LOCAL_ASSIGNMENT_SERVER_HOSTNAME, - DEFAULT_DOMAIN_SERVER_PORT); +const HifiSockAddr DEFAULT_LOCAL_ASSIGNMENT_SOCKET = HifiSockAddr(QHostAddress(LOCAL_ASSIGNMENT_SERVER_HOSTNAME), + DEFAULT_DOMAIN_SERVER_PORT); void NodeList::sendAssignment(Assignment& assignment) { unsigned char assignmentPacket[MAX_PACKET_SIZE]; @@ -633,14 +623,16 @@ void NodeList::sendAssignment(Assignment& assignment) { int numHeaderBytes = populateTypeAndVersion(assignmentPacket, assignmentPacketType); int numAssignmentBytes = assignment.packToBuffer(assignmentPacket + numHeaderBytes); - sockaddr* assignmentServerSocket = (_assignmentServerSocket == NULL) - ? (sockaddr*) &DEFAULT_LOCAL_ASSIGNMENT_SOCKET - : _assignmentServerSocket; + const HifiSockAddr* assignmentServerSocket = _assignmentServerSocket.isNull() + ? &DEFAULT_LOCAL_ASSIGNMENT_SOCKET + : &_assignmentServerSocket; - _nodeSocket.send(assignmentServerSocket, assignmentPacket, numHeaderBytes + numAssignmentBytes); + _nodeSocket.writeDatagram((char*) assignmentPacket, numHeaderBytes + numAssignmentBytes, + assignmentServerSocket->getAddress(), + assignmentServerSocket->getPort()); } -void NodeList::pingPublicAndLocalSocketsForInactiveNode(Node* node) const { +void NodeList::pingPublicAndLocalSocketsForInactiveNode(Node* node) { uint64_t currentTime = 0; @@ -652,11 +644,14 @@ void NodeList::pingPublicAndLocalSocketsForInactiveNode(Node* node) const { memcpy(pingPacket + numHeaderBytes, ¤tTime, sizeof(currentTime)); // send the ping packet to the local and public sockets for this node - _nodeSocket.send(node->getLocalSocket(), pingPacket, sizeof(pingPacket)); - _nodeSocket.send(node->getPublicSocket(), pingPacket, sizeof(pingPacket)); + _nodeSocket.writeDatagram((char*) pingPacket, sizeof(pingPacket), + node->getLocalSocket().getAddress(), node->getLocalSocket().getPort()); + _nodeSocket.writeDatagram((char*) pingPacket, sizeof(pingPacket), + node->getPublicSocket().getAddress(), node->getPublicSocket().getPort()); } -Node* NodeList::addOrUpdateNode(const QUuid& uuid, char nodeType, sockaddr* publicSocket, sockaddr* localSocket) { +Node* NodeList::addOrUpdateNode(const QUuid& uuid, char nodeType, + const HifiSockAddr& publicSocket, const HifiSockAddr& localSocket) { NodeList::iterator node = end(); for (node = begin(); node != end(); node++) { @@ -684,12 +679,12 @@ Node* NodeList::addOrUpdateNode(const QUuid& uuid, char nodeType, sockaddr* publ } // check if we need to change this node's public or local sockets - if (!socketMatch(publicSocket, node->getPublicSocket())) { + if (publicSocket != node->getPublicSocket()) { node->setPublicSocket(publicSocket); qDebug() << "Public socket change for node" << *node << "\n"; } - if (!socketMatch(localSocket, node->getLocalSocket())) { + if (localSocket != node->getLocalSocket()) { node->setLocalSocket(localSocket); qDebug() << "Local socket change for node" << *node << "\n"; } @@ -725,7 +720,8 @@ unsigned NodeList::broadcastToNodes(unsigned char* broadcastData, size_t dataByt if (memchr(nodeTypes, node->getType(), numNodeTypes)) { if (getNodeActiveSocketOrPing(&(*node))) { // we know which socket is good for this node, send there - _nodeSocket.send(node->getActiveSocket(), broadcastData, dataBytes); + _nodeSocket.writeDatagram((char*) broadcastData, dataBytes, + node->getActiveSocket()->getAddress(), node->getActiveSocket()->getPort()); ++n; } } @@ -751,7 +747,7 @@ void NodeList::possiblyPingInactiveNodes() { } } -sockaddr* NodeList::getNodeActiveSocketOrPing(Node* node) { +const HifiSockAddr* NodeList::getNodeActiveSocketOrPing(Node* node) { if (node->getActiveSocket()) { return node->getActiveSocket(); } else { @@ -760,15 +756,15 @@ sockaddr* NodeList::getNodeActiveSocketOrPing(Node* node) { } } -void NodeList::activateSocketFromNodeCommunication(sockaddr *nodeAddress) { +void NodeList::activateSocketFromNodeCommunication(const HifiSockAddr& nodeAddress) { for(NodeList::iterator node = begin(); node != end(); node++) { if (!node->getActiveSocket()) { // 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)) { + if (node->getPublicSocket() == nodeAddress) { node->activatePublicSocket(); break; - } else if (socketMatch(node->getLocalSocket(), nodeAddress)) { + } else if (node->getLocalSocket() == nodeAddress) { node->activateLocalSocket(); break; } @@ -969,7 +965,7 @@ void NodeListIterator::skipDeadAndStopIncrement() { void NodeList::addDomainListener(DomainChangeListener* listener) { _domainListeners.push_back(listener); - QString domain = _domainHostname.isEmpty() ? _domainIP.toString() : _domainHostname; + QString domain = _domainHostname.isEmpty() ? _domainSockAddr.getAddress().toString() : _domainHostname; listener->domainChanged(domain); } diff --git a/libraries/shared/src/NodeList.h b/libraries/shared/src/NodeList.h index 1e7b181cb0..7efc4b2682 100644 --- a/libraries/shared/src/NodeList.h +++ b/libraries/shared/src/NodeList.h @@ -15,11 +15,11 @@ #include #include +#include #include #include "Node.h" #include "NodeTypes.h" -#include "UDPSocket.h" #ifdef _WIN32 #include "pthread.h" @@ -45,6 +45,7 @@ const char LOCAL_ASSIGNMENT_SERVER_HOSTNAME[] = "localhost"; const int MAX_SILENT_DOMAIN_SERVER_CHECK_INS = 5; class Assignment; +class HifiSockAddr; class NodeListIterator; // Callers who want to hook add/kill callbacks should implement this class @@ -75,19 +76,15 @@ public: const QString& getDomainHostname() const { return _domainHostname; } void setDomainHostname(const QString& domainHostname); - const QHostAddress& getDomainIP() const { return _domainIP; } - void setDomainIP(const QHostAddress& domainIP) { _domainIP = domainIP; } - void setDomainIPToLocalhost() { _domainIP = QHostAddress(INADDR_LOOPBACK); } + const QHostAddress& getDomainIP() const { return _domainSockAddr.getAddress(); } + void setDomainIPToLocalhost() { _domainSockAddr.setAddress(QHostAddress(INADDR_LOOPBACK)); } - unsigned short getDomainPort() const { return _domainPort; } - void setDomainPort(unsigned short domainPort) { _domainPort = domainPort; } + unsigned short getDomainPort() const { return _domainSockAddr.getPort(); } const QUuid& getOwnerUUID() const { return _ownerUUID; } void setOwnerUUID(const QUuid& ownerUUID) { _ownerUUID = ownerUUID; } - UDPSocket* getNodeSocket() { return &_nodeSocket; } - - unsigned short int getSocketListenPort() const { return _nodeSocket.getListeningPort(); } + QUdpSocket& getNodeSocket() { return _nodeSocket; } void(*linkedDataCreateCallback)(Node *); @@ -104,23 +101,23 @@ public: void sendDomainServerCheckIn(); int processDomainServerList(unsigned char *packetData, size_t dataBytes); - void setAssignmentServerSocket(sockaddr* serverSocket) { _assignmentServerSocket = serverSocket; } + void setAssignmentServerSocket(const HifiSockAddr& serverSocket) { _assignmentServerSocket = serverSocket; } void sendAssignment(Assignment& assignment); - void pingPublicAndLocalSocketsForInactiveNode(Node* node) const; + void pingPublicAndLocalSocketsForInactiveNode(Node* node); void sendKillNode(const char* nodeTypes, int numNodeTypes); - Node* nodeWithAddress(sockaddr *senderAddress); + Node* nodeWithAddress(const HifiSockAddr& senderSockAddr); Node* nodeWithUUID(const QUuid& nodeUUID); - Node* addOrUpdateNode(const QUuid& uuid, char nodeType, sockaddr* publicSocket, sockaddr* localSocket); + Node* addOrUpdateNode(const QUuid& uuid, char nodeType, const HifiSockAddr& publicSocket, const HifiSockAddr& localSocket); void killNode(Node* node, bool mustLockNode = true); - void processNodeData(sockaddr *senderAddress, unsigned char *packetData, size_t dataBytes); - void processBulkNodeData(sockaddr *senderAddress, unsigned char *packetData, int numTotalBytes); + void processNodeData(const HifiSockAddr& senderSockAddr, unsigned char *packetData, size_t dataBytes); + void processBulkNodeData(const HifiSockAddr& senderSockAddr, unsigned char *packetData, int numTotalBytes); - int updateNodeWithData(Node *node, sockaddr* senderAddress, unsigned char *packetData, int dataBytes); + int updateNodeWithData(Node *node, const HifiSockAddr& senderSockAddr, unsigned char *packetData, int dataBytes); unsigned broadcastToNodes(unsigned char *broadcastData, size_t dataBytes, const char* nodeTypes, int numNodeTypes); @@ -143,7 +140,7 @@ public: void removeDomainListener(DomainChangeListener* listener); void possiblyPingInactiveNodes(); - sockaddr* getNodeActiveSocketOrPing(Node* node); + const HifiSockAddr* getNodeActiveSocketOrPing(Node* node); private: static NodeList* _sharedInstance; @@ -160,25 +157,23 @@ private: void processKillNode(unsigned char* packetData, size_t dataBytes); QString _domainHostname; - QHostAddress _domainIP; - unsigned short _domainPort; + HifiSockAddr _domainSockAddr; Node** _nodeBuckets[MAX_NUM_NODES / NODES_PER_BUCKET]; int _numNodes; - UDPSocket _nodeSocket; + QUdpSocket _nodeSocket; char _ownerType; char* _nodeTypesOfInterest; QUuid _ownerUUID; pthread_t removeSilentNodesThread; pthread_t checkInWithDomainServerThread; int _numNoReplyDomainCheckIns; - sockaddr* _assignmentServerSocket; - QHostAddress _publicAddress; - uint16_t _publicPort; + HifiSockAddr _assignmentServerSocket; + HifiSockAddr _publicSockAddr; bool _hasCompletedInitialSTUNFailure; unsigned int _stunRequestsSinceSuccess; - void activateSocketFromNodeCommunication(sockaddr *nodeAddress); - void timePingReply(sockaddr *nodeAddress, unsigned char *packetData); + void activateSocketFromNodeCommunication(const HifiSockAddr& nodeSockAddr); + void timePingReply(const HifiSockAddr& nodeAddress, unsigned char *packetData); std::vector _hooks; std::vector _domainListeners; diff --git a/libraries/shared/src/PacketSender.cpp b/libraries/shared/src/PacketSender.cpp index 3c0b0c80d8..f829a80ac0 100644 --- a/libraries/shared/src/PacketSender.cpp +++ b/libraries/shared/src/PacketSender.cpp @@ -44,7 +44,7 @@ PacketSender::PacketSender(PacketSenderNotify* notify, int packetsPerSecond) : } -void PacketSender::queuePacketForSending(sockaddr& address, unsigned char* packetData, ssize_t packetLength) { +void PacketSender::queuePacketForSending(const HifiSockAddr& address, unsigned char* packetData, ssize_t packetLength) { NetworkPacket packet(address, packetData, packetLength); lock(); _packets.push_back(packet); @@ -334,9 +334,9 @@ bool PacketSender::nonThreadedProcess() { unlock(); // send the packet through the NodeList... - UDPSocket* nodeSocket = NodeList::getInstance()->getNodeSocket(); - - nodeSocket->send(&temporary.getAddress(), temporary.getData(), temporary.getLength()); + NodeList::getInstance()->getNodeSocket().writeDatagram((char*) temporary.getData(), temporary.getLength(), + temporary.getSockAddr().getAddress(), + temporary.getSockAddr().getPort()); packetsSentThisCall++; _packetsOverCheckInterval++; _totalPacketsSent++; diff --git a/libraries/shared/src/PacketSender.h b/libraries/shared/src/PacketSender.h index 1731f70cbf..b05e42d11b 100644 --- a/libraries/shared/src/PacketSender.h +++ b/libraries/shared/src/PacketSender.h @@ -38,11 +38,11 @@ public: PacketSender(PacketSenderNotify* notify = NULL, int packetsPerSecond = DEFAULT_PACKETS_PER_SECOND); /// Add packet to outbound queue. - /// \param sockaddr& address the destination address + /// \param HifiSockAddr& address the destination address /// \param packetData pointer to data /// \param ssize_t packetLength size of data /// \thread any thread, typically the application thread - void queuePacketForSending(sockaddr& address, unsigned char* packetData, ssize_t packetLength); + void queuePacketForSending(const HifiSockAddr& address, unsigned char* packetData, ssize_t packetLength); void setPacketsPerSecond(int packetsPerSecond) { _packetsPerSecond = std::max(MINIMUM_PACKETS_PER_SECOND, packetsPerSecond); } diff --git a/libraries/shared/src/ReceivedPacketProcessor.cpp b/libraries/shared/src/ReceivedPacketProcessor.cpp index a46cd36dbe..4ad869460e 100644 --- a/libraries/shared/src/ReceivedPacketProcessor.cpp +++ b/libraries/shared/src/ReceivedPacketProcessor.cpp @@ -16,9 +16,9 @@ ReceivedPacketProcessor::ReceivedPacketProcessor() { _dontSleep = false; } -void ReceivedPacketProcessor::queueReceivedPacket(sockaddr& address, unsigned char* packetData, ssize_t packetLength) { +void ReceivedPacketProcessor::queueReceivedPacket(const HifiSockAddr& address, unsigned char* packetData, ssize_t packetLength) { // Make sure our Node and NodeList knows we've heard from this node. - Node* node = NodeList::getInstance()->nodeWithAddress(&address); + Node* node = NodeList::getInstance()->nodeWithAddress(address); if (node) { node->setLastHeardMicrostamp(usecTimestampNow()); } @@ -44,7 +44,7 @@ bool ReceivedPacketProcessor::process() { NetworkPacket temporary = packet; // make a copy of the packet in case the vector is resized on us _packets.erase(_packets.begin()); // remove the oldest packet unlock(); // let others add to the packets - processPacket(temporary.getAddress(), temporary.getData(), temporary.getLength()); // process our temporary copy + processPacket(temporary.getSockAddr(), temporary.getData(), temporary.getLength()); // process our temporary copy } return isStillRunning(); // keep running till they terminate us } diff --git a/libraries/shared/src/ReceivedPacketProcessor.h b/libraries/shared/src/ReceivedPacketProcessor.h index f36473ae12..621204025e 100644 --- a/libraries/shared/src/ReceivedPacketProcessor.h +++ b/libraries/shared/src/ReceivedPacketProcessor.h @@ -24,7 +24,7 @@ public: /// \param packetData pointer to received data /// \param ssize_t packetLength size of received data /// \thread network receive thread - void queueReceivedPacket(sockaddr& senderAddress, unsigned char* packetData, ssize_t packetLength); + void queueReceivedPacket(const HifiSockAddr& senderSockAddr, unsigned char* packetData, ssize_t packetLength); /// Are there received packets waiting to be processed bool hasPacketsToProcess() const { return _packets.size() > 0; } @@ -38,7 +38,7 @@ protected: /// \param packetData pointer to received data /// \param ssize_t packetLength size of received data /// \thread "this" individual processing thread - virtual void processPacket(sockaddr& senderAddress, unsigned char* packetData, ssize_t packetLength) = 0; + virtual void processPacket(const HifiSockAddr& senderAddress, unsigned char* packetData, ssize_t packetLength) = 0; /// Implements generic processing behavior for this thread. virtual bool process(); diff --git a/libraries/shared/src/UDPSocket.cpp b/libraries/shared/src/UDPSocket.cpp deleted file mode 100644 index 1318fbc4a5..0000000000 --- a/libraries/shared/src/UDPSocket.cpp +++ /dev/null @@ -1,293 +0,0 @@ -// -// UDPSocket.cpp -// interface -// -// Created by Stephen Birarda on 1/28/13. -// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. -// - -#include -#include -#include -#include -#include - -#ifdef _WIN32 -#include "Syssocket.h" -#else -#include -#include -#include -#include -#endif - -#include -#include -#include - -#include "Logging.h" -#include "UDPSocket.h" - -sockaddr_in destSockaddr, senderAddress; - -bool socketMatch(const sockaddr* first, const sockaddr* second) { - if (first != NULL && second != NULL) { - // utility function that indicates if two sockets are equivalent - - // currently only compares two IPv4 addresses - // expandable to IPv6 by adding else if for AF_INET6 - - if (first->sa_family != second->sa_family) { - // not the same family, can't be equal - return false; - } else if (first->sa_family == AF_INET) { - const sockaddr_in *firstIn = (const sockaddr_in *) first; - 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; - } else { - return false; - } - } else { - return false; - } -} - -int packSocket(unsigned char* packStore, in_addr_t inAddress, in_port_t networkOrderPort) { - packStore[0] = inAddress >> 24; - packStore[1] = inAddress >> 16; - packStore[2] = inAddress >> 8; - packStore[3] = inAddress; - - packStore[4] = networkOrderPort >> 8; - packStore[5] = networkOrderPort; - - return 6; // could be dynamically more if we need IPv6 -} - -int packSocket(unsigned char* packStore, sockaddr* socketToPack) { - return packSocket(packStore, ((sockaddr_in*) socketToPack)->sin_addr.s_addr, ((sockaddr_in*) socketToPack)->sin_port); -} - -int unpackSocket(const unsigned char* packedData, sockaddr* unpackDestSocket) { - sockaddr_in* destinationSocket = (sockaddr_in*) unpackDestSocket; - destinationSocket->sin_family = AF_INET; - destinationSocket->sin_addr.s_addr = (packedData[0] << 24) + (packedData[1] << 16) + (packedData[2] << 8) + packedData[3]; - destinationSocket->sin_port = (packedData[4] << 8) + packedData[5]; - return 6; // this could be more if we ever need IPv6 -} - -void copySocketToEmptySocketPointer(sockaddr** destination, const sockaddr* source) { - // create a new sockaddr or sockaddr_in depending on what type of address this is - if (source->sa_family == AF_INET) { - *destination = (sockaddr*) new sockaddr_in; - memcpy(*destination, source, sizeof(sockaddr_in)); - } else { - *destination = (sockaddr*) new sockaddr_in6; - memcpy(*destination, source, sizeof(sockaddr_in6)); - } -} - -int getLocalAddress() { - - static int localAddress = 0; - - if (localAddress == 0) { - foreach(const QNetworkInterface &interface, QNetworkInterface::allInterfaces()) { - if (interface.flags() & QNetworkInterface::IsUp - && interface.flags() & QNetworkInterface::IsRunning - && interface.flags() & ~QNetworkInterface::IsLoopBack) { - // we've decided that this is the active NIC - // enumerate it's addresses to grab the IPv4 address - foreach(const QNetworkAddressEntry &entry, interface.addressEntries()) { - // make sure it's an IPv4 address that isn't the loopback - if (entry.ip().protocol() == QAbstractSocket::IPv4Protocol && !entry.ip().isLoopback()) { - qDebug("Node's local address is %s\n", entry.ip().toString().toLocal8Bit().constData()); - - // set our localAddress and break out - localAddress = htonl(entry.ip().toIPv4Address()); - break; - } - } - } - - if (localAddress != 0) { - break; - } - } - } - - // return the looked up local address - return localAddress; -} - -unsigned short loadBufferWithSocketInfo(char* addressBuffer, sockaddr* socket) { - if (socket != NULL) { - char* copyBuffer = inet_ntoa(((sockaddr_in*) socket)->sin_addr); - memcpy(addressBuffer, copyBuffer, strlen(copyBuffer)); - return htons(((sockaddr_in*) socket)->sin_port); - } else { - const char* unknownAddress = "Unknown"; - memcpy(addressBuffer, unknownAddress, strlen(unknownAddress)); - return 0; - } -} - -sockaddr_in socketForHostnameAndHostOrderPort(const char* hostname, unsigned short port) { - struct hostent* pHostInfo; - sockaddr_in newSocket = {}; - - if ((pHostInfo = gethostbyname(hostname))) { - memcpy(&newSocket.sin_addr, pHostInfo->h_addr_list[0], pHostInfo->h_length); - } - - if (port != 0) { - newSocket.sin_port = htons(port); - } - - return newSocket; -} - -UDPSocket::UDPSocket(unsigned short int listeningPort) : - _listeningPort(listeningPort), - blocking(true) -{ - init(); - // create the socket - handle = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); - - if (handle <= 0) { - qDebug("Failed to create socket.\n"); - return; - } - - destSockaddr.sin_family = AF_INET; - - // bind the socket to the passed listeningPort - sockaddr_in bind_address; - bind_address.sin_family = AF_INET; - bind_address.sin_addr.s_addr = INADDR_ANY; - bind_address.sin_port = htons((uint16_t) _listeningPort); - - if (bind(handle, (const sockaddr*) &bind_address, sizeof(sockaddr_in)) < 0) { - qDebug("Failed to bind socket to port %hu.\n", _listeningPort); - return; - } - - // if we requested an ephemeral port, get the actual port - if (listeningPort == 0) { - socklen_t addressLength = sizeof(sockaddr_in); - getsockname(handle, (sockaddr*) &bind_address, &addressLength); - _listeningPort = ntohs(bind_address.sin_port); - } - - const int DEFAULT_BLOCKING_SOCKET_TIMEOUT_USECS = 0.5 * 1000000; - setBlockingReceiveTimeoutInUsecs(DEFAULT_BLOCKING_SOCKET_TIMEOUT_USECS); - - qDebug("Created UDP Socket listening on %hd\n", _listeningPort); -} - -UDPSocket::~UDPSocket() { -#ifdef _WIN32 - closesocket(handle); -#else - close(handle); -#endif -} - -bool UDPSocket::init() { -#ifdef _WIN32 - WORD wVersionRequested; - WSADATA wsaData; - int err; - - wVersionRequested = MAKEWORD( 2, 2 ); - - err = WSAStartup( wVersionRequested, &wsaData ); - if ( err != 0 ) { - /* Tell the user that we could not find a usable */ - /* WinSock DLL. */ - return false; - } - - /* Confirm that the WinSock DLL supports 2.2.*/ - /* Note that if the DLL supports versions later */ - /* than 2.2 in addition to 2.2, it will still return */ - /* 2.2 in wVersion since that is the version we */ - /* requested. */ - - if ( LOBYTE( wsaData.wVersion ) != 2 || - HIBYTE( wsaData.wVersion ) != 2 ) { - /* Tell the user that we could not find a usable */ - /* WinSock DLL. */ - WSACleanup(); - return false; - } -#endif - return true; -} - -void UDPSocket::setBlocking(bool blocking) { - this->blocking = blocking; - -#ifdef _WIN32 - u_long mode = blocking ? 0 : 1; - ioctlsocket(handle, FIONBIO, &mode); -#else - int flags = fcntl(handle, F_GETFL, 0); - fcntl(handle, F_SETFL, blocking ? (flags & ~O_NONBLOCK) : (flags | O_NONBLOCK)); -#endif -} - -void UDPSocket::setBlockingReceiveTimeoutInUsecs(int timeoutUsecs) { - struct timeval tv = {timeoutUsecs / 1000000, timeoutUsecs % 1000000}; - setsockopt(handle, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv)); -} - -// Receive data on this socket with retrieving address of sender -bool UDPSocket::receive(void* receivedData, ssize_t* receivedBytes) const { - return receive((sockaddr*) &senderAddress, receivedData, receivedBytes); -} - -// Receive data on this socket with the address of the sender -bool UDPSocket::receive(sockaddr* recvAddress, void* receivedData, ssize_t* receivedBytes) const { - -#ifdef _WIN32 - int addressSize = sizeof(*recvAddress); -#else - socklen_t addressSize = sizeof(*recvAddress); -#endif - *receivedBytes = recvfrom(handle, static_cast(receivedData), MAX_BUFFER_LENGTH_BYTES, - 0, recvAddress, &addressSize); - - return (*receivedBytes > 0); -} - -int UDPSocket::send(sockaddr* destAddress, const void* data, size_t byteLength) const { - if (destAddress) { - // send data via UDP - int sent_bytes = sendto(handle, (const char*)data, byteLength, - 0, (sockaddr *) destAddress, sizeof(sockaddr_in)); - - if (sent_bytes != byteLength) { - qDebug("Failed to send packet: %s\n", strerror(errno)); - return false; - } - - return sent_bytes; - } else { - qDebug("UDPSocket send called with NULL destination address - Likely a node with no active socket.\n"); - return 0; - } - -} - -int UDPSocket::send(const char* destAddress, int destPort, const void* data, size_t byteLength) const { - - // change address and port on reusable global to passed variables - destSockaddr.sin_addr.s_addr = inet_addr(destAddress); - destSockaddr.sin_port = htons((uint16_t)destPort); - - return send((sockaddr *)&destSockaddr, data, byteLength); -} diff --git a/libraries/shared/src/UDPSocket.h b/libraries/shared/src/UDPSocket.h deleted file mode 100644 index b177fd4e30..0000000000 --- a/libraries/shared/src/UDPSocket.h +++ /dev/null @@ -1,53 +0,0 @@ -// -// UDPSocket.h -// interface -// -// Created by Stephen Birarda on 1/28/13. -// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. -// - -#ifndef __interface__UDPSocket__ -#define __interface__UDPSocket__ - -#ifdef _WIN32 -#include "Syssocket.h" -#else -#include -#include -#endif - -#define MAX_BUFFER_LENGTH_BYTES 1500 - -class UDPSocket { -public: - UDPSocket(unsigned short int listeningPort); - ~UDPSocket(); - - bool init(); - unsigned short int getListeningPort() const { return _listeningPort; } - - void setBlocking(bool blocking); - bool isBlocking() const { return blocking; } - void setBlockingReceiveTimeoutInUsecs(int timeoutUsecs); - - int send(sockaddr* destAddress, const void* data, size_t byteLength) const; - int send(const char* destAddress, int destPort, const void* data, size_t byteLength) const; - - bool receive(void* receivedData, ssize_t* receivedBytes) const; - bool receive(sockaddr* recvAddress, void* receivedData, ssize_t* receivedBytes) const; -private: - int handle; - unsigned short int _listeningPort; - bool blocking; -}; - -bool socketMatch(const sockaddr* first, const sockaddr* second); -int packSocket(unsigned char* packStore, in_addr_t inAddress, in_port_t networkOrderPort); -int packSocket(unsigned char* packStore, sockaddr* socketToPack); -int unpackSocket(const unsigned char* packedData, sockaddr* unpackDestSocket); -void copySocketToEmptySocketPointer(sockaddr** destination, const sockaddr* source); -int getLocalAddress(); -unsigned short loadBufferWithSocketInfo(char* addressBuffer, sockaddr* socket); -sockaddr_in socketForHostnameAndHostOrderPort(const char* hostname, unsigned short port = 0); - -#endif /* defined(__interface__UDPSocket__) */ diff --git a/libraries/voxel-server-library/src/VoxelSendThread.cpp b/libraries/voxel-server-library/src/VoxelSendThread.cpp index fe2842d6d7..7e0e9551b9 100644 --- a/libraries/voxel-server-library/src/VoxelSendThread.cpp +++ b/libraries/voxel-server-library/src/VoxelSendThread.cpp @@ -103,22 +103,28 @@ int VoxelSendThread::handlePacketSend(Node* node, VoxelNodeData* nodeData, int& statsMessageLength += nodeData->getPacketLength(); // actually send it - NodeList::getInstance()->getNodeSocket()->send(node->getActiveSocket(), statsMessage, statsMessageLength); + NodeList::getInstance()->getNodeSocket().writeDatagram((char*) statsMessage, statsMessageLength, + node->getActiveSocket()->getAddress(), + node->getActiveSocket()->getPort()); } else { // not enough room in the packet, send two packets - NodeList::getInstance()->getNodeSocket()->send(node->getActiveSocket(), statsMessage, statsMessageLength); + NodeList::getInstance()->getNodeSocket().writeDatagram((char*) statsMessage, statsMessageLength, + node->getActiveSocket()->getAddress(), + node->getActiveSocket()->getPort()); trueBytesSent += statsMessageLength; truePacketsSent++; packetsSent++; - NodeList::getInstance()->getNodeSocket()->send(node->getActiveSocket(), - nodeData->getPacket(), nodeData->getPacketLength()); + NodeList::getInstance()->getNodeSocket().writeDatagram((char*) nodeData->getPacket(), nodeData->getPacketLength(), + node->getActiveSocket()->getAddress(), + node->getActiveSocket()->getPort()); } nodeData->stats.markAsSent(); } else { // just send the voxel packet - NodeList::getInstance()->getNodeSocket()->send(node->getActiveSocket(), - nodeData->getPacket(), nodeData->getPacketLength()); + NodeList::getInstance()->getNodeSocket().writeDatagram((char*) nodeData->getPacket(), nodeData->getPacketLength(), + node->getActiveSocket()->getAddress(), + node->getActiveSocket()->getPort()); } // remember to track our stats nodeData->stats.packetSent(nodeData->getPacketLength()); @@ -335,7 +341,9 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod envPacketLength += _myServer->getEnvironmentData(i)->getBroadcastData(_tempOutputBuffer + envPacketLength); } - NodeList::getInstance()->getNodeSocket()->send(node->getActiveSocket(), _tempOutputBuffer, envPacketLength); + NodeList::getInstance()->getNodeSocket().writeDatagram((char*) _tempOutputBuffer, envPacketLength, + node->getActiveSocket()->getAddress(), + node->getActiveSocket()->getPort()); trueBytesSent += envPacketLength; truePacketsSent++; packetsSentThisInterval++; diff --git a/libraries/voxel-server-library/src/VoxelServer.cpp b/libraries/voxel-server-library/src/VoxelServer.cpp index cf650117f2..4be9183cb9 100644 --- a/libraries/voxel-server-library/src/VoxelServer.cpp +++ b/libraries/voxel-server-library/src/VoxelServer.cpp @@ -618,7 +618,7 @@ void VoxelServer::run() { qDebug("packetsPerSecond=%s PACKETS_PER_CLIENT_PER_INTERVAL=%d\n", packetsPerSecond, _packetsPerClientPerInterval); } - sockaddr senderAddress; + HifiSockAddr senderSockAddr; unsigned char* packetData = new unsigned char[MAX_PACKET_SIZE]; ssize_t packetLength; @@ -668,7 +668,9 @@ void VoxelServer::run() { // ping our inactive nodes to punch holes with them nodeList->possiblyPingInactiveNodes(); - if (nodeList->getNodeSocket()->receive(&senderAddress, packetData, &packetLength) && + if ((packetLength = nodeList->getNodeSocket().readDatagram((char*) packetData, MAX_PACKET_SIZE, + senderSockAddr.getAddressPointer(), + senderSockAddr.getPortPointer())) && packetVersionMatch(packetData)) { int numBytesPacketHeader = numBytesForPacketHeader(packetData); @@ -682,7 +684,7 @@ void VoxelServer::run() { Node* node = nodeList->nodeWithUUID(nodeUUID); if (node) { - nodeList->updateNodeWithData(node, &senderAddress, packetData, packetLength); + nodeList->updateNodeWithData(node, senderSockAddr, packetData, packetLength); if (!node->getActiveSocket()) { // we don't have an active socket for this node, but they're talking to us // this means they've heard from us and can reply, let's assume public is active @@ -695,7 +697,7 @@ void VoxelServer::run() { } } else if (packetData[0] == PACKET_TYPE_VOXEL_JURISDICTION_REQUEST) { if (_jurisdictionSender) { - _jurisdictionSender->queueReceivedPacket(senderAddress, packetData, packetLength); + _jurisdictionSender->queueReceivedPacket(senderSockAddr, packetData, packetLength); } } else if (_voxelServerPacketProcessor && (packetData[0] == PACKET_TYPE_SET_VOXEL @@ -730,10 +732,10 @@ void VoxelServer::run() { } } - _voxelServerPacketProcessor->queueReceivedPacket(senderAddress, packetData, packetLength); + _voxelServerPacketProcessor->queueReceivedPacket(senderSockAddr, packetData, packetLength); } else { // let processNodeData handle it. - NodeList::getInstance()->processNodeData(&senderAddress, packetData, packetLength); + NodeList::getInstance()->processNodeData(senderSockAddr, packetData, packetLength); } } } diff --git a/libraries/voxel-server-library/src/VoxelServerPacketProcessor.cpp b/libraries/voxel-server-library/src/VoxelServerPacketProcessor.cpp index 2581c923f5..46cea75212 100644 --- a/libraries/voxel-server-library/src/VoxelServerPacketProcessor.cpp +++ b/libraries/voxel-server-library/src/VoxelServerPacketProcessor.cpp @@ -39,7 +39,8 @@ void VoxelServerPacketProcessor::resetStats() { } -void VoxelServerPacketProcessor::processPacket(sockaddr& senderAddress, unsigned char* packetData, ssize_t packetLength) { +void VoxelServerPacketProcessor::processPacket(const HifiSockAddr& senderSockAddr, + unsigned char* packetData, ssize_t packetLength) { bool debugProcessPacket = _myServer->wantsVerboseDebug(); @@ -135,7 +136,7 @@ void VoxelServerPacketProcessor::processPacket(sockaddr& senderAddress, unsigned } // Make sure our Node and NodeList knows we've heard from this node. - Node* senderNode = NodeList::getInstance()->nodeWithAddress(&senderAddress); + Node* senderNode = NodeList::getInstance()->nodeWithAddress(senderSockAddr); QUuid& nodeUUID = DEFAULT_NODE_ID_REF; if (senderNode) { senderNode->setLastHeardMicrostamp(usecTimestampNow()); @@ -170,7 +171,7 @@ void VoxelServerPacketProcessor::processPacket(sockaddr& senderAddress, unsigned _myServer->getServerTree().unlock(); // Make sure our Node and NodeList knows we've heard from this node. - Node* node = NodeList::getInstance()->nodeWithAddress(&senderAddress); + Node* node = NodeList::getInstance()->nodeWithAddress(senderSockAddr); if (node) { node->setLastHeardMicrostamp(usecTimestampNow()); } @@ -199,7 +200,7 @@ void VoxelServerPacketProcessor::processPacket(sockaddr& senderAddress, unsigned } // Make sure our Node and NodeList knows we've heard from this node. - Node* node = NodeList::getInstance()->nodeWithAddress(&senderAddress); + Node* node = NodeList::getInstance()->nodeWithAddress(senderSockAddr); if (node) { node->setLastHeardMicrostamp(usecTimestampNow()); } diff --git a/libraries/voxel-server-library/src/VoxelServerPacketProcessor.h b/libraries/voxel-server-library/src/VoxelServerPacketProcessor.h index 2408e0dd60..4abdbad284 100644 --- a/libraries/voxel-server-library/src/VoxelServerPacketProcessor.h +++ b/libraries/voxel-server-library/src/VoxelServerPacketProcessor.h @@ -63,7 +63,7 @@ public: NodeToSenderStatsMap& getSingleSenderStats() { return _singleSenderStats; } protected: - virtual void processPacket(sockaddr& senderAddress, unsigned char* packetData, ssize_t packetLength); + virtual void processPacket(const HifiSockAddr& senderSockAddr, unsigned char* packetData, ssize_t packetLength); private: void trackInboundPackets(const QUuid& nodeUUID, int sequence, uint64_t transitTime, diff --git a/libraries/voxels/src/JurisdictionListener.cpp b/libraries/voxels/src/JurisdictionListener.cpp index 223b602dfa..3213e11940 100644 --- a/libraries/voxels/src/JurisdictionListener.cpp +++ b/libraries/voxels/src/JurisdictionListener.cpp @@ -48,7 +48,7 @@ bool JurisdictionListener::queueJurisdictionRequest() { NodeList* nodeList = NodeList::getInstance(); for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { if (nodeList->getNodeActiveSocketOrPing(&(*node)) && node->getType() == NODE_TYPE_VOXEL_SERVER) { - sockaddr* nodeAddress = node->getActiveSocket(); + const HifiSockAddr* nodeAddress = node->getActiveSocket(); PacketSender::queuePacketForSending(*nodeAddress, bufferOut, sizeOut); nodeCount++; } @@ -64,9 +64,9 @@ bool JurisdictionListener::queueJurisdictionRequest() { return isStillRunning(); } -void JurisdictionListener::processPacket(sockaddr& senderAddress, unsigned char* packetData, ssize_t packetLength) { +void JurisdictionListener::processPacket(const HifiSockAddr& senderAddress, unsigned char* packetData, ssize_t packetLength) { if (packetData[0] == PACKET_TYPE_VOXEL_JURISDICTION) { - Node* node = NodeList::getInstance()->nodeWithAddress(&senderAddress); + Node* node = NodeList::getInstance()->nodeWithAddress(senderAddress); if (node) { QUuid nodeUUID = node->getUUID(); JurisdictionMap map; diff --git a/libraries/voxels/src/JurisdictionListener.h b/libraries/voxels/src/JurisdictionListener.h index 7376c9196f..a05601169b 100644 --- a/libraries/voxels/src/JurisdictionListener.h +++ b/libraries/voxels/src/JurisdictionListener.h @@ -45,7 +45,7 @@ protected: /// \param packetData pointer to received data /// \param ssize_t packetLength size of received data /// \thread "this" individual processing thread - virtual void processPacket(sockaddr& senderAddress, unsigned char* packetData, ssize_t packetLength); + virtual void processPacket(const HifiSockAddr& senderAddress, unsigned char* packetData, ssize_t packetLength); private: NodeToJurisdictionMap _jurisdictions; diff --git a/libraries/voxels/src/JurisdictionSender.cpp b/libraries/voxels/src/JurisdictionSender.cpp index 3d3a3bec6f..9bb729f66a 100644 --- a/libraries/voxels/src/JurisdictionSender.cpp +++ b/libraries/voxels/src/JurisdictionSender.cpp @@ -29,9 +29,9 @@ JurisdictionSender::~JurisdictionSender() { } -void JurisdictionSender::processPacket(sockaddr& senderAddress, unsigned char* packetData, ssize_t packetLength) { +void JurisdictionSender::processPacket(const HifiSockAddr& senderAddress, unsigned char* packetData, ssize_t packetLength) { if (packetData[0] == PACKET_TYPE_VOXEL_JURISDICTION_REQUEST) { - Node* node = NodeList::getInstance()->nodeWithAddress(&senderAddress); + Node* node = NodeList::getInstance()->nodeWithAddress(senderAddress); if (node) { QUuid nodeUUID = node->getUUID(); lockRequestingNodes(); @@ -66,7 +66,7 @@ bool JurisdictionSender::process() { Node* node = NodeList::getInstance()->nodeWithUUID(nodeUUID); if (node->getActiveSocket() != NULL) { - sockaddr* nodeAddress = node->getActiveSocket(); + const HifiSockAddr* nodeAddress = node->getActiveSocket(); queuePacketForSending(*nodeAddress, bufferOut, sizeOut); nodeCount++; } diff --git a/libraries/voxels/src/JurisdictionSender.h b/libraries/voxels/src/JurisdictionSender.h index f223621b87..9a7ea3c760 100644 --- a/libraries/voxels/src/JurisdictionSender.h +++ b/libraries/voxels/src/JurisdictionSender.h @@ -32,7 +32,7 @@ public: virtual bool process(); protected: - virtual void processPacket(sockaddr& senderAddress, unsigned char* packetData, ssize_t packetLength); + virtual void processPacket(const HifiSockAddr& senderAddress, unsigned char* packetData, ssize_t packetLength); /// Locks all the resources of the thread. void lockRequestingNodes() { pthread_mutex_lock(&_requestingNodeMutex); } diff --git a/libraries/voxels/src/VoxelEditPacketSender.cpp b/libraries/voxels/src/VoxelEditPacketSender.cpp index ec7ea3810b..bfc42da63f 100644 --- a/libraries/voxels/src/VoxelEditPacketSender.cpp +++ b/libraries/voxels/src/VoxelEditPacketSender.cpp @@ -123,7 +123,7 @@ void VoxelEditPacketSender::queuePacketToNode(const QUuid& nodeUUID, unsigned ch if (node->getType() == NODE_TYPE_VOXEL_SERVER && ((node->getUUID() == nodeUUID) || (nodeUUID.isNull()))) { if (nodeList->getNodeActiveSocketOrPing(&(*node))) { - sockaddr* nodeAddress = node->getActiveSocket(); + const HifiSockAddr* nodeAddress = node->getActiveSocket(); queuePacketForSending(*nodeAddress, buffer, length); // debugging output... diff --git a/pairing-server/CMakeLists.txt b/pairing-server/CMakeLists.txt index 5e0adcb378..b1fbdf82dc 100644 --- a/pairing-server/CMakeLists.txt +++ b/pairing-server/CMakeLists.txt @@ -5,9 +5,13 @@ set(MACRO_DIR ${ROOT_DIR}/cmake/macros) set(TARGET_NAME pairing-server) +find_package(Qt5Network REQUIRED) + include(${MACRO_DIR}/SetupHifiProject.cmake) setup_hifi_project(${TARGET_NAME} TRUE) +qt5_use_modules(${TARGET_NAME} Network) + # link the shared hifi library include(${MACRO_DIR}/LinkHifiLibrary.cmake) link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR}) \ No newline at end of file diff --git a/pairing-server/src/main.cpp b/pairing-server/src/main.cpp index 0422251403..4efff8f588 100644 --- a/pairing-server/src/main.cpp +++ b/pairing-server/src/main.cpp @@ -11,17 +11,20 @@ #include #include -#include #include +#include + +#include + const int PAIRING_SERVER_LISTEN_PORT = 7247; const int MAX_PACKET_SIZE_BYTES = 1400; struct PairableDevice { char identifier[64]; char name[64]; - sockaddr_in sendingSocket; - sockaddr_in localSocket; + HifiSockAddr sendingSocket; + HifiSockAddr localSocket; }; struct RequestingClient { @@ -29,7 +32,7 @@ struct RequestingClient { int port; }; -UDPSocket serverSocket(PAIRING_SERVER_LISTEN_PORT); +QUdpSocket serverSocket; PairableDevice* lastDevice = NULL; RequestingClient* lastClient = NULL; @@ -47,17 +50,20 @@ void sendLastClientToLastDevice() { char pairData[INET_ADDRSTRLEN + 6] = {}; int bytesWritten = sprintf(pairData, "%s:%d", ::lastClient->address, ::lastClient->port); - ::serverSocket.send((sockaddr*) &::lastDevice->sendingSocket, pairData, bytesWritten); + ::serverSocket.writeDatagram(pairData, bytesWritten, + ::lastDevice->sendingSocket.getAddress(), ::lastDevice->sendingSocket.getPort()); } int main(int argc, const char* argv[]) { - sockaddr_in senderSocket; + serverSocket.bind(QHostAddress::LocalHost, PAIRING_SERVER_LISTEN_PORT); + + HifiSockAddr senderSockAddr; char senderData[MAX_PACKET_SIZE_BYTES] = {}; - ssize_t receivedBytes = 0; while (true) { - if (::serverSocket.receive((sockaddr*) &senderSocket, &senderData, &receivedBytes)) { + if (::serverSocket.readDatagram(senderData, MAX_PACKET_SIZE_BYTES, + senderSockAddr.getAddressPointer(), senderSockAddr.getPortPointer())) { if (senderData[0] == 'A') { // this is a device reporting itself as available @@ -76,12 +82,11 @@ int main(int argc, const char* argv[]) { // if we have fewer than 3 matches the packet wasn't properly formatted // setup the localSocket for the pairing device - tempDevice.localSocket.sin_family = AF_INET; - inet_pton(AF_INET, deviceAddress, &::lastDevice); - tempDevice.localSocket.sin_port = socketPort; + tempDevice.localSocket.setAddress(QHostAddress(deviceAddress)); + tempDevice.localSocket.setPort(socketPort); // store this device's sending socket so we can talk back to it - tempDevice.sendingSocket = senderSocket; + tempDevice.sendingSocket = senderSockAddr; // push this new device into the vector printf("New last device is %s (%s) at %s:%d\n", diff --git a/space-server/CMakeLists.txt b/space-server/CMakeLists.txt deleted file mode 100644 index c821992378..0000000000 --- a/space-server/CMakeLists.txt +++ /dev/null @@ -1,13 +0,0 @@ -cmake_minimum_required(VERSION 2.8) - -set(ROOT_DIR ..) -set(MACRO_DIR ${ROOT_DIR}/cmake/macros) - -set(TARGET_NAME space-server) - -include(${MACRO_DIR}/SetupHifiProject.cmake) - -setup_hifi_project(${TARGET_NAME} TRUE) - -include(${MACRO_DIR}/LinkHifiLibrary.cmake) -link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR}) \ No newline at end of file diff --git a/space-server/example.data.txt b/space-server/example.data.txt deleted file mode 100644 index 065017c308..0000000000 --- a/space-server/example.data.txt +++ /dev/null @@ -1,2 +0,0 @@ -0 00000100001011101110 domain4.highfidelity.co domain4 -0 00000100110100010001 domain3.highfidelity.co domain3 diff --git a/space-server/src/TreeNode.cpp b/space-server/src/TreeNode.cpp deleted file mode 100644 index 7326b2db0d..0000000000 --- a/space-server/src/TreeNode.cpp +++ /dev/null @@ -1,20 +0,0 @@ -// -// TreeNode.cpp -// hifi -// -// Created by Stephen Birarda on 2/13/13. -// -// - -#include "TreeNode.h" - -std::string EMPTY_STRING = ""; - -TreeNode::TreeNode() { - for (int i = 0; i < CHILDREN_PER_NODE; ++i) { - child[i] = NULL; - } - - hostname = NULL; - nickname = NULL; -} \ No newline at end of file diff --git a/space-server/src/TreeNode.h b/space-server/src/TreeNode.h deleted file mode 100644 index ad766d953f..0000000000 --- a/space-server/src/TreeNode.h +++ /dev/null @@ -1,26 +0,0 @@ -// -// TreeNode.h -// hifi -// -// Created by Stephen Birarda on 2/13/13. -// -// - -#ifndef __hifi__TreeNode__ -#define __hifi__TreeNode__ - -#include - -const int CHILDREN_PER_NODE = 8; - -class TreeNode { -public: - TreeNode(); - - TreeNode *child[CHILDREN_PER_NODE]; - char *hostname; - char *nickname; - int domain_id; -}; - -#endif /* defined(__hifi__TreeNode__) */ diff --git a/space-server/src/main.cpp b/space-server/src/main.cpp deleted file mode 100644 index 24d73da9c1..0000000000 --- a/space-server/src/main.cpp +++ /dev/null @@ -1,160 +0,0 @@ -// -// main.cpp -// space -// -// Created by Leonardo Murillo on 2/6/13. -// Copyright (c) 2013 HighFidelity, Inc. All rights reserved. -// - -#include -#include -#include -#include - -#include "TreeNode.h" -#include "UDPSocket.h" - -const char *CONFIG_FILE = "/Users/birarda/code/worklist/checkouts/hifi/space/example.data.txt"; -const unsigned short SPACE_LISTENING_PORT = 55551; -const short MAX_NAME_LENGTH = 255; - -const char ROOT_HOSTNAME[] = "root.highfidelity.co"; -const char ROOT_NICKNAME[] = "root"; - -const size_t PACKET_LENGTH_BYTES = 1024; - -sockaddr_in destAddress; -socklen_t destLength = sizeof(destAddress); - -char *lastKnownHostname; - -TreeNode rootNode; -UDPSocket spaceSocket(SPACE_LISTENING_PORT); - -TreeNode *findOrCreateNode(int lengthInBits, - unsigned char *addressBytes, - char *hostname, - char *nickname, - int domainID) { - - TreeNode *currentNode = &rootNode; - - for (int i = 0; i < lengthInBits; i += 3) { - unsigned char octet; - - if (i%8 < 6) { - octet = addressBytes[i/8] << i%8 >> (5); - } else { - octet = (addressBytes[i/8] << i >> (11 - i)) | (addressBytes[i/8 + 1] >> (11 - i + 2)); - } - - if (currentNode->child[octet] == NULL) { - currentNode->child[octet] = new TreeNode; - } else if (currentNode->child[octet]->hostname != NULL) { - lastKnownHostname = currentNode->child[octet]->hostname; - } - - currentNode = currentNode->child[octet]; - } - - if (currentNode->hostname == NULL) { - currentNode->hostname = hostname; - currentNode->nickname = nickname; - } - - return currentNode; -}; - -bool loadSpaceData(void) { - FILE *configFile = std::fopen(CONFIG_FILE, "r"); - char formatString[10]; - - if (configFile == NULL) { - std::cout << "Unable to load config file!\n"; - return false; - } else { - char *lengthBitString = new char[8]; - int itemsRead = 0; - - while ((itemsRead = fscanf(configFile, "0 %8c", lengthBitString)) > 0) { - - // calculate the number of bits in the address and bits required for padding - unsigned long threeBitCodes = strtoul(lengthBitString, NULL, 2); - int bitsInAddress = threeBitCodes * 3; - int paddingBits = 8 - (bitsInAddress % 8); - int addressByteLength = (bitsInAddress + paddingBits) / 8; - - // create an unsigned char * to hold the padded address - unsigned char *paddedAddress = new unsigned char[addressByteLength]; - - char *fullByteBitString = new char[8]; - - for (int c = 0; c < addressByteLength; c++) { - if (c + 1 == addressByteLength && paddingBits > 0) { - // this is the last byte, and we need some padding bits - // pull as many bits as are left - int goodBits = 8 - paddingBits; - sprintf(formatString, "%%%dc", goodBits); - itemsRead = fscanf(configFile, formatString, fullByteBitString); - - // fill out the rest with zeros - memset(fullByteBitString + goodBits, '0', paddingBits); - } else { - // pull 8 bits (which will be one byte) from the file - itemsRead = fscanf(configFile, "%8c", fullByteBitString); - } - - // set the corresponding value in the unsigned char array - *(paddedAddress + c) = strtoul(fullByteBitString, NULL, 2); - } - - char *nodeHostname = new char[MAX_NAME_LENGTH]; - char *nodeNickname = new char[MAX_NAME_LENGTH]; - itemsRead = fscanf(configFile, "%s %s\n", nodeHostname, nodeNickname); - - findOrCreateNode(bitsInAddress, paddedAddress, nodeHostname, nodeNickname, 0); - } - - std::fclose(configFile); - - return true; - } -} - -int main (int argc, const char *argv[]) { - - setvbuf(stdout, NULL, _IOLBF, 0); - - unsigned char packetData[PACKET_LENGTH_BYTES]; - ssize_t receivedBytes = 0; - - rootNode.hostname = new char[MAX_NAME_LENGTH]; - rootNode.nickname = new char[MAX_NAME_LENGTH]; - - strcpy(rootNode.hostname, ROOT_HOSTNAME); - strcpy(rootNode.nickname, ROOT_NICKNAME); - - loadSpaceData(); - - std::cout << "[DEBUG] Listening for Datagrams" << std::endl; - - while (true) { - if (spaceSocket.receive((sockaddr *)&destAddress, &packetData, &receivedBytes)) { - unsigned long lengthInBits; - lengthInBits = packetData[0] * 3; - - unsigned char addressData[sizeof(packetData)-1]; - for (int i = 0; i < sizeof(packetData)-1; ++i) { - addressData[i] = packetData[i+1]; - } - - TreeNode *thisNode = findOrCreateNode(lengthInBits, addressData, NULL, NULL, 0); - char *hostnameToSend = (thisNode->hostname == NULL) - ? lastKnownHostname - : thisNode->hostname; - - spaceSocket.send((sockaddr *)&destAddress, &hostnameToSend, sizeof(hostnameToSend)); - } - } -} - From 6d04d0cee107f3f78ed099ed12875058e0c03dab Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 2 Dec 2013 13:37:43 -0800 Subject: [PATCH 06/31] replace a missing capture of received bytes --- assignment-client/src/avatars/AvatarMixer.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index 787771a269..d3e1a5bd57 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -129,8 +129,9 @@ void AvatarMixer::run() { nodeList->possiblyPingInactiveNodes(); - if (nodeList->getNodeSocket().readDatagram((char*) packetData, MAX_PACKET_SIZE, - nodeSockAddr.getAddressPointer(), nodeSockAddr.getPortPointer()) && + if ((receivedBytes = nodeList->getNodeSocket().readDatagram((char*) packetData, MAX_PACKET_SIZE, + nodeSockAddr.getAddressPointer(), + nodeSockAddr.getPortPointer())) && packetVersionMatch(packetData)) { switch (packetData[0]) { case PACKET_TYPE_HEAD_DATA: From 49191826af6cc7fafdf2308a8e87a6250b7e91a0 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 2 Dec 2013 14:08:49 -0800 Subject: [PATCH 07/31] add check for pending datagrams before read --- animation-server/src/main.cpp | 7 ++++--- assignment-client/src/Agent.cpp | 9 +++++---- assignment-client/src/audio/AudioMixer.cpp | 6 ++++-- assignment-client/src/avatars/AvatarMixer.cpp | 3 ++- assignment-client/src/main.cpp | 2 +- domain-server/src/DomainServer.cpp | 5 ++--- interface/src/Application.cpp | 9 +++++---- libraries/shared/src/HifiSockAddr.cpp | 10 ++++++---- libraries/shared/src/NodeList.cpp | 6 +++--- libraries/shared/src/NodeList.h | 2 +- libraries/voxel-server-library/src/VoxelServer.cpp | 9 +++++---- pairing-server/src/main.cpp | 5 +++-- 12 files changed, 41 insertions(+), 32 deletions(-) diff --git a/animation-server/src/main.cpp b/animation-server/src/main.cpp index 281c761c00..a77be03aa5 100644 --- a/animation-server/src/main.cpp +++ b/animation-server/src/main.cpp @@ -858,9 +858,10 @@ int main(int argc, const char * argv[]) } // Nodes sending messages to us... - if ((receivedBytes = nodeList->getNodeSocket().readDatagram((char*) packetData, MAX_PACKET_SIZE, - nodeSockAddr.getAddressPointer(), - nodeSockAddr.getPortPointer())) && + if (nodeList->getNodeSocket().hasPendingDatagrams() + && (receivedBytes = nodeList->getNodeSocket().readDatagram((char*) packetData, MAX_PACKET_SIZE, + nodeSockAddr.getAddressPointer(), + nodeSockAddr.getPortPointer())) && packetVersionMatch(packetData)) { if (packetData[0] == PACKET_TYPE_VOXEL_JURISDICTION) { diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index bedaab87c4..24934397ad 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -147,10 +147,11 @@ void Agent::run() { qDebug() << "Uncaught exception at line" << line << ":" << engine.uncaughtException().toString() << "\n"; } - while ((receivedBytes = NodeList::getInstance()->getNodeSocket().readDatagram((char*) receivedBytes, - MAX_PACKET_SIZE, - senderSockAddr.getAddressPointer(), - senderSockAddr.getPortPointer())) + while (nodeList->getNodeSocket().hasPendingDatagrams() && + (receivedBytes = nodeList->getNodeSocket().readDatagram((char*) receivedBytes, + MAX_PACKET_SIZE, + senderSockAddr.getAddressPointer(), + senderSockAddr.getPortPointer())) && packetVersionMatch(receivedData)) { if (receivedData[0] == PACKET_TYPE_VOXEL_JURISDICTION) { voxelScripter.getJurisdictionListener()->queueReceivedPacket(senderSockAddr, diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 0d11a63344..3c325e7258 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -312,8 +312,10 @@ void AudioMixer::run() { } // pull any new audio data from nodes off of the network stack - while ((receivedBytes = nodeList->getNodeSocket().readDatagram((char*) packetData, MAX_PACKET_SIZE, - nodeSockAddr.getAddressPointer(), nodeSockAddr.getPortPointer())) && + while (nodeList->getNodeSocket().hasPendingDatagrams() && + (receivedBytes = nodeList->getNodeSocket().readDatagram((char*) packetData, MAX_PACKET_SIZE, + nodeSockAddr.getAddressPointer(), + nodeSockAddr.getPortPointer())) && packetVersionMatch(packetData)) { if (packetData[0] == PACKET_TYPE_MICROPHONE_AUDIO_NO_ECHO || packetData[0] == PACKET_TYPE_MICROPHONE_AUDIO_WITH_ECHO diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index d3e1a5bd57..9a629a8ef6 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -129,7 +129,8 @@ void AvatarMixer::run() { nodeList->possiblyPingInactiveNodes(); - if ((receivedBytes = nodeList->getNodeSocket().readDatagram((char*) packetData, MAX_PACKET_SIZE, + if (nodeList->getNodeSocket().hasPendingDatagrams() && + (receivedBytes = nodeList->getNodeSocket().readDatagram((char*) packetData, MAX_PACKET_SIZE, nodeSockAddr.getAddressPointer(), nodeSockAddr.getPortPointer())) && packetVersionMatch(packetData)) { diff --git a/assignment-client/src/main.cpp b/assignment-client/src/main.cpp index cef77610c4..ae4f569f83 100644 --- a/assignment-client/src/main.cpp +++ b/assignment-client/src/main.cpp @@ -127,7 +127,7 @@ int main(int argc, char* argv[]) { // set the custom hostname or default if it wasn't passed if (!customAssignmentServerHostname) { - customAssignmentServerHostname = LOCAL_ASSIGNMENT_SERVER_HOSTNAME; + customAssignmentServerHostname = DEFAULT_ASSIGNMENT_SERVER_HOSTNAME; } ::customAssignmentSocket = HifiSockAddr(customAssignmentServerHostname, assignmentServerPort); diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 9aba991f16..175118ef7d 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -589,8 +589,6 @@ int DomainServer::run() { quint16 senderPort; HifiSockAddr nodePublicAddress, nodeLocalAddress; - - nodeList->startSilentNodeRemovalThread(); if (!_staticAssignmentFile.exists() || _voxelServerConfig) { @@ -613,7 +611,8 @@ int DomainServer::run() { gettimeofday(&startTime, NULL); while (true) { - while (nodeList->getNodeSocket().readDatagram((char*) packetData, MAX_PACKET_SIZE, &senderAddress, &senderPort) && + while (nodeList->getNodeSocket().hasPendingDatagrams() + && nodeList->getNodeSocket().readDatagram((char*) packetData, MAX_PACKET_SIZE, &senderAddress, &senderPort) && packetVersionMatch(packetData)) { if (packetData[0] == PACKET_TYPE_DOMAIN_REPORT_FOR_DUTY || packetData[0] == PACKET_TYPE_DOMAIN_LIST_REQUEST) { // this is an RFD or domain list request packet, and there is a version match diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 84f72242c4..c601005e8b 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -4305,10 +4305,11 @@ void* Application::networkReceive(void* args) { Application* app = Application::getInstance(); while (!app->_stopNetworkReceiveThread) { - if ((bytesReceived = NodeList::getInstance()->getNodeSocket().readDatagram((char*) app->_incomingPacket, - MAX_PACKET_SIZE, - senderSockAddr.getAddressPointer(), - senderSockAddr.getPortPointer()))) { + if (NodeList::getInstance()->getNodeSocket().hasPendingDatagrams() && + (bytesReceived = NodeList::getInstance()->getNodeSocket().readDatagram((char*) app->_incomingPacket, + MAX_PACKET_SIZE, + senderSockAddr.getAddressPointer(), + senderSockAddr.getPortPointer()))) { app->_packetCount++; app->_bytesCount += bytesReceived; diff --git a/libraries/shared/src/HifiSockAddr.cpp b/libraries/shared/src/HifiSockAddr.cpp index 542b4c2e52..66ae200026 100644 --- a/libraries/shared/src/HifiSockAddr.cpp +++ b/libraries/shared/src/HifiSockAddr.cpp @@ -33,10 +33,12 @@ HifiSockAddr::HifiSockAddr(const HifiSockAddr& otherSockAddr) { HifiSockAddr::HifiSockAddr(const QString& hostname, quint16 hostOrderPort) { // lookup the IP by the hostname QHostInfo hostInfo = QHostInfo::fromName(hostname); - if (!hostInfo.addresses().isEmpty()) { - // use the first IP address - _address = hostInfo.addresses().first(); - _port = hostOrderPort; } + foreach(const QHostAddress& address, hostInfo.addresses()) { + if (address.protocol() == QAbstractSocket::IPv4Protocol) { + _address = address; + _port = hostOrderPort; + } + } } HifiSockAddr& HifiSockAddr::operator=(const HifiSockAddr& rhsSockAddr) { diff --git a/libraries/shared/src/NodeList.cpp b/libraries/shared/src/NodeList.cpp index 59135b05d4..8bd714cd18 100644 --- a/libraries/shared/src/NodeList.cpp +++ b/libraries/shared/src/NodeList.cpp @@ -611,8 +611,6 @@ int NodeList::processDomainServerList(unsigned char* packetData, size_t dataByte return readNodes; } -const HifiSockAddr DEFAULT_LOCAL_ASSIGNMENT_SOCKET = HifiSockAddr(QHostAddress(LOCAL_ASSIGNMENT_SERVER_HOSTNAME), - DEFAULT_DOMAIN_SERVER_PORT); void NodeList::sendAssignment(Assignment& assignment) { unsigned char assignmentPacket[MAX_PACKET_SIZE]; @@ -623,8 +621,10 @@ void NodeList::sendAssignment(Assignment& assignment) { int numHeaderBytes = populateTypeAndVersion(assignmentPacket, assignmentPacketType); int numAssignmentBytes = assignment.packToBuffer(assignmentPacket + numHeaderBytes); + static HifiSockAddr DEFAULT_ASSIGNMENT_SOCKET(DEFAULT_ASSIGNMENT_SERVER_HOSTNAME, DEFAULT_DOMAIN_SERVER_PORT); + const HifiSockAddr* assignmentServerSocket = _assignmentServerSocket.isNull() - ? &DEFAULT_LOCAL_ASSIGNMENT_SOCKET + ? &DEFAULT_ASSIGNMENT_SOCKET : &_assignmentServerSocket; _nodeSocket.writeDatagram((char*) assignmentPacket, numHeaderBytes + numAssignmentBytes, diff --git a/libraries/shared/src/NodeList.h b/libraries/shared/src/NodeList.h index 7efc4b2682..0d5d84ecfa 100644 --- a/libraries/shared/src/NodeList.h +++ b/libraries/shared/src/NodeList.h @@ -40,7 +40,7 @@ const int MAX_HOSTNAME_BYTES = 256; extern const QString DEFAULT_DOMAIN_HOSTNAME; extern const unsigned short DEFAULT_DOMAIN_SERVER_PORT; -const char LOCAL_ASSIGNMENT_SERVER_HOSTNAME[] = "localhost"; +const char DEFAULT_ASSIGNMENT_SERVER_HOSTNAME[] = "localhost"; const int MAX_SILENT_DOMAIN_SERVER_CHECK_INS = 5; diff --git a/libraries/voxel-server-library/src/VoxelServer.cpp b/libraries/voxel-server-library/src/VoxelServer.cpp index 4be9183cb9..5fd87f52ec 100644 --- a/libraries/voxel-server-library/src/VoxelServer.cpp +++ b/libraries/voxel-server-library/src/VoxelServer.cpp @@ -668,10 +668,11 @@ void VoxelServer::run() { // ping our inactive nodes to punch holes with them nodeList->possiblyPingInactiveNodes(); - if ((packetLength = nodeList->getNodeSocket().readDatagram((char*) packetData, MAX_PACKET_SIZE, - senderSockAddr.getAddressPointer(), - senderSockAddr.getPortPointer())) && - packetVersionMatch(packetData)) { + if (nodeList->getNodeSocket().hasPendingDatagrams() + && (packetLength = nodeList->getNodeSocket().readDatagram((char*) packetData, MAX_PACKET_SIZE, + senderSockAddr.getAddressPointer(), + senderSockAddr.getPortPointer())) + && packetVersionMatch(packetData)) { int numBytesPacketHeader = numBytesForPacketHeader(packetData); diff --git a/pairing-server/src/main.cpp b/pairing-server/src/main.cpp index 4efff8f588..609f9412e9 100644 --- a/pairing-server/src/main.cpp +++ b/pairing-server/src/main.cpp @@ -62,8 +62,9 @@ int main(int argc, const char* argv[]) { char senderData[MAX_PACKET_SIZE_BYTES] = {}; while (true) { - if (::serverSocket.readDatagram(senderData, MAX_PACKET_SIZE_BYTES, - senderSockAddr.getAddressPointer(), senderSockAddr.getPortPointer())) { + if (::serverSocket.hasPendingDatagrams() + && ::serverSocket.readDatagram(senderData, MAX_PACKET_SIZE_BYTES, + senderSockAddr.getAddressPointer(), senderSockAddr.getPortPointer())) { if (senderData[0] == 'A') { // this is a device reporting itself as available From 1e279cf99c46038c1d50b89e1182bca129a05550 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 2 Dec 2013 16:34:38 -0800 Subject: [PATCH 08/31] hook AudioMixer to new event-driven assignment setup --- assignment-client/src/AssignmentClient.cpp | 89 ++++++++- assignment-client/src/AssignmentClient.h | 3 + assignment-client/src/audio/AudioMixer.cpp | 219 ++++++++------------- assignment-client/src/audio/AudioMixer.h | 11 +- libraries/shared/src/Assignment.h | 3 +- libraries/shared/src/HifiSockAddr.h | 2 + libraries/shared/src/NodeData.h | 2 +- libraries/shared/src/NodeList.cpp | 52 +++-- libraries/shared/src/NodeList.h | 9 +- 9 files changed, 223 insertions(+), 167 deletions(-) diff --git a/assignment-client/src/AssignmentClient.cpp b/assignment-client/src/AssignmentClient.cpp index f694795466..d136d9eb6e 100644 --- a/assignment-client/src/AssignmentClient.cpp +++ b/assignment-client/src/AssignmentClient.cpp @@ -26,7 +26,8 @@ AssignmentClient::AssignmentClient(int &argc, char **argv, const HifiSockAddr& customAssignmentServerSocket, const char* requestAssignmentPool) : QCoreApplication(argc, argv), - _requestAssignment(Assignment::RequestCommand, requestAssignmentType, requestAssignmentPool) + _requestAssignment(Assignment::RequestCommand, requestAssignmentType, requestAssignmentPool), + _currentAssignment(NULL) { // set the logging target to the the CHILD_TARGET_NAME Logging::setTargetName(ASSIGNMENT_CLIENT_TARGET_NAME); @@ -45,8 +46,92 @@ AssignmentClient::AssignmentClient(int &argc, char **argv, QTimer* timer = new QTimer(this); connect(timer, SIGNAL(timeout()), SLOT(sendAssignmentRequest())); timer->start(ASSIGNMENT_REQUEST_INTERVAL_MSECS); + + // connect our readPendingDatagrams method to the readyRead() signal of the socket + connect(&nodeList->getNodeSocket(), SIGNAL(readyRead()), this, SLOT(readPendingDatagrams())); } void AssignmentClient::sendAssignmentRequest() { - NodeList::getInstance()->sendAssignment(_requestAssignment); + if (!_currentAssignment) { + NodeList::getInstance()->sendAssignment(_requestAssignment); + } +} + +void AssignmentClient::readPendingDatagrams() { + NodeList* nodeList = NodeList::getInstance(); + + static unsigned char packetData[1500]; + static qint64 receivedBytes = 0; + static HifiSockAddr senderSockAddr; + + while (nodeList->getNodeSocket().hasPendingDatagrams()) { + + if ((receivedBytes = nodeList->getNodeSocket().readDatagram((char*) packetData, MAX_PACKET_SIZE, + senderSockAddr.getAddressPointer(), + senderSockAddr.getPortPointer())) + && packetVersionMatch(packetData)) { + + if (packetData[0] == PACKET_TYPE_DEPLOY_ASSIGNMENT || packetData[0] == PACKET_TYPE_CREATE_ASSIGNMENT) { + + if (_currentAssignment) { + qDebug() << "Dropping received assignment since we are currently running one.\n"; + } else { + // construct the deployed assignment from the packet data + _currentAssignment = AssignmentFactory::unpackAssignment(packetData, receivedBytes); + + qDebug() << "Received an assignment -" << *_currentAssignment << "\n"; + + // switch our nodelist domain IP and port to whoever sent us the assignment + if (packetData[0] == PACKET_TYPE_CREATE_ASSIGNMENT) { + nodeList->setDomainSockAddr(senderSockAddr); + nodeList->setOwnerUUID(_currentAssignment->getUUID()); + + qDebug("Destination IP for assignment is %s\n", + nodeList->getDomainIP().toString().toStdString().c_str()); + + // start the deployed assignment + QThread *workerThread = new QThread(this); + + connect(workerThread, SIGNAL(started()), _currentAssignment, SLOT(run())); + connect(_currentAssignment, SIGNAL(finished()), workerThread, SLOT(quit())); + connect(_currentAssignment, SIGNAL(finished()), _currentAssignment, SLOT(deleteLater())); + connect(_currentAssignment, SIGNAL(finished()), workerThread, SLOT(deleteLater())); + _currentAssignment->moveToThread(workerThread); + + // Starts an event loop, and emits workerThread->started() + workerThread->start(); + } else { + qDebug("Received a bad destination socket for assignment.\n"); + } + } + } else if (_currentAssignment) { + + qRegisterMetaType("HifiSockAddr"); + + // have the threaded current assignment handle this datagram + QMetaObject::invokeMethod(_currentAssignment, "processDatagram", Qt::QueuedConnection, + Q_ARG(const QByteArray&, QByteArray((char*) packetData, receivedBytes)), + Q_ARG(const HifiSockAddr&, senderSockAddr)); + } else { + // have the NodeList attempt to handle it + nodeList->processNodeData(senderSockAddr, packetData, receivedBytes); + } + } + } +} + +void AssignmentClient::assignmentCompleted() { + qDebug("Assignment finished or never started - waiting for new assignment\n"); + + // the _currentAssignment is being deleted, set our pointer to NULL + _currentAssignment = NULL; + + NodeList* nodeList = NodeList::getInstance(); + + // reset our NodeList by switching back to unassigned and clearing the list + nodeList->setOwnerType(NODE_TYPE_UNASSIGNED); + nodeList->reset(); + + // reset the logging target to the the CHILD_TARGET_NAME + Logging::setTargetName(ASSIGNMENT_CLIENT_TARGET_NAME); } diff --git a/assignment-client/src/AssignmentClient.h b/assignment-client/src/AssignmentClient.h index e7072e816a..b826f40a63 100644 --- a/assignment-client/src/AssignmentClient.h +++ b/assignment-client/src/AssignmentClient.h @@ -20,8 +20,11 @@ public: const char* requestAssignmentPool = NULL); private slots: void sendAssignmentRequest(); + void readPendingDatagrams(); + void assignmentCompleted(); private: Assignment _requestAssignment; + Assignment* _currentAssignment; }; #endif /* defined(__hifi__AssignmentClient__) */ diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 3c325e7258..451904bb48 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -32,6 +32,8 @@ #include #include +#include + #include #include #include @@ -51,7 +53,7 @@ const short JITTER_BUFFER_MSECS = 12; const short JITTER_BUFFER_SAMPLES = JITTER_BUFFER_MSECS * (SAMPLE_RATE / 1000.0); -const unsigned int BUFFER_SEND_INTERVAL_USECS = floorf((BUFFER_LENGTH_SAMPLES_PER_CHANNEL / SAMPLE_RATE) * 1000000); +const unsigned int BUFFER_SEND_INTERVAL_MSECS = floorf((BUFFER_LENGTH_SAMPLES_PER_CHANNEL / SAMPLE_RATE) * 1000); const int MAX_SAMPLE_VALUE = std::numeric_limits::max(); const int MIN_SAMPLE_VALUE = std::numeric_limits::min(); @@ -217,6 +219,80 @@ void AudioMixer::prepareMixForListeningNode(Node* node) { } } + +void AudioMixer::processDatagram(const QByteArray& dataByteArray, const HifiSockAddr& senderSockAddr) { + // pull any new audio data from nodes off of the network stack + if (dataByteArray.data()[0] == PACKET_TYPE_MICROPHONE_AUDIO_NO_ECHO + || dataByteArray.data()[0] == PACKET_TYPE_MICROPHONE_AUDIO_WITH_ECHO + || dataByteArray.data()[0] == PACKET_TYPE_INJECT_AUDIO) { + QUuid nodeUUID = QUuid::fromRfc4122(dataByteArray.mid(numBytesForPacketHeader((unsigned char*) dataByteArray.data()), + NUM_BYTES_RFC4122_UUID)); + + NodeList* nodeList = NodeList::getInstance(); + + Node* matchingNode = nodeList->nodeWithUUID(nodeUUID); + + if (matchingNode) { + nodeList->updateNodeWithData(matchingNode, senderSockAddr, (unsigned char*) dataByteArray.data(), dataByteArray.size()); + + if (!matchingNode->getActiveSocket()) { + // we don't have an active socket for this node, but they're talking to us + // this means they've heard from us and can reply, let's assume public is active + matchingNode->activatePublicSocket(); + } + } + } else { + // let processNodeData handle it. + NodeList::getInstance()->processNodeData(senderSockAddr, (unsigned char*) dataByteArray.data(), dataByteArray.size()); + } +} + + +void AudioMixer::checkInWithDomainServerOrExit() { + if (NodeList::getInstance()->getNumNoReplyDomainCheckIns() == MAX_SILENT_DOMAIN_SERVER_CHECK_INS) { + emit finished(); + } else { + NodeList::getInstance()->sendDomainServerCheckIn(); + } +} + +void AudioMixer::sendClientMixes() { + NodeList* nodeList = NodeList::getInstance(); + + // get the NodeList to ping any inactive nodes, for hole punching + nodeList->possiblyPingInactiveNodes(); + + int numBytesPacketHeader = numBytesForPacketHeader((unsigned char*) &PACKET_TYPE_MIXED_AUDIO); + unsigned char clientPacket[BUFFER_LENGTH_BYTES_STEREO + numBytesPacketHeader]; + populateTypeAndVersion(clientPacket, PACKET_TYPE_MIXED_AUDIO); + + for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { + if (node->getLinkedData()) { + ((AudioMixerClientData*) node->getLinkedData())->checkBuffersBeforeFrameSend(JITTER_BUFFER_SAMPLES); + } + } + + for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { + if (node->getType() == NODE_TYPE_AGENT && node->getActiveSocket() && node->getLinkedData() + && ((AudioMixerClientData*) node->getLinkedData())->getAvatarAudioRingBuffer()) { + prepareMixForListeningNode(&(*node)); + + memcpy(clientPacket + numBytesPacketHeader, _clientSamples, sizeof(_clientSamples)); + nodeList->getNodeSocket().writeDatagram((char*) clientPacket, sizeof(clientPacket), + node->getActiveSocket()->getAddress(), + node->getActiveSocket()->getPort()); + } + } + + // push forward the next output pointers for any audio buffers we used + for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { + if (node->getLinkedData()) { + ((AudioMixerClientData*) node->getLinkedData())->pushBuffersAfterFrameSend(); + } + } +} + + void AudioMixer::run() { // change the logging target name while this is running Logging::setTargetName(AUDIO_MIXER_LOGGING_TARGET_NAME); @@ -227,140 +303,17 @@ void AudioMixer::run() { const char AUDIO_MIXER_NODE_TYPES_OF_INTEREST[2] = { NODE_TYPE_AGENT, NODE_TYPE_AUDIO_INJECTOR }; nodeList->setNodeTypesOfInterest(AUDIO_MIXER_NODE_TYPES_OF_INTEREST, sizeof(AUDIO_MIXER_NODE_TYPES_OF_INTEREST)); - ssize_t receivedBytes = 0; - nodeList->linkedDataCreateCallback = attachNewBufferToNode; - nodeList->startSilentNodeRemovalThread(); + QTimer* domainServerTimer = new QTimer(this); + connect(domainServerTimer, SIGNAL(timeout()), this, SLOT(checkInWithDomainServerOrExit())); + domainServerTimer->start(DOMAIN_SERVER_CHECK_IN_USECS / 1000); - unsigned char packetData[MAX_PACKET_SIZE] = {}; + QTimer* silentNodeTimer = new QTimer(this); + connect(silentNodeTimer, SIGNAL(timeout()), nodeList, SLOT(removeSilentNodes())); + silentNodeTimer->start(NODE_SILENCE_THRESHOLD_USECS / 1000); - HifiSockAddr nodeSockAddr; - - int nextFrame = 0; - timeval startTime; - - int numBytesPacketHeader = numBytesForPacketHeader((unsigned char*) &PACKET_TYPE_MIXED_AUDIO); - unsigned char clientPacket[BUFFER_LENGTH_BYTES_STEREO + numBytesPacketHeader]; - populateTypeAndVersion(clientPacket, PACKET_TYPE_MIXED_AUDIO); - - gettimeofday(&startTime, NULL); - - timeval lastDomainServerCheckIn = {}; - - timeval beginSendTime, endSendTime; - float sumFrameTimePercentages = 0.0f; - int numStatCollections = 0; - - // if we'll be sending stats, call the Logstash::socket() method to make it load the logstash IP outside the loop - if (Logging::shouldSendStats()) { - Logging::socket(); - } - - while (true) { - if (NodeList::getInstance()->getNumNoReplyDomainCheckIns() == MAX_SILENT_DOMAIN_SERVER_CHECK_INS) { - break; - } - - if (Logging::shouldSendStats()) { - gettimeofday(&beginSendTime, NULL); - } - - // 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(); - - if (Logging::shouldSendStats() && numStatCollections > 0) { - // if we should be sending stats to Logstash send the appropriate average now - const char MIXER_LOGSTASH_METRIC_NAME[] = "audio-mixer-frame-time-usage"; - - float averageFrameTimePercentage = sumFrameTimePercentages / numStatCollections; - Logging::stashValue(STAT_TYPE_TIMER, MIXER_LOGSTASH_METRIC_NAME, averageFrameTimePercentage); - - sumFrameTimePercentages = 0.0f; - numStatCollections = 0; - } - } - - // get the NodeList to ping any inactive nodes, for hole punching - nodeList->possiblyPingInactiveNodes(); - - for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { - if (node->getLinkedData()) { - ((AudioMixerClientData*) node->getLinkedData())->checkBuffersBeforeFrameSend(JITTER_BUFFER_SAMPLES); - } - } - - for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { - if (node->getType() == NODE_TYPE_AGENT && node->getActiveSocket() && node->getLinkedData() - && ((AudioMixerClientData*) node->getLinkedData())->getAvatarAudioRingBuffer()) { - prepareMixForListeningNode(&(*node)); - - memcpy(clientPacket + numBytesPacketHeader, _clientSamples, sizeof(_clientSamples)); - nodeList->getNodeSocket().writeDatagram((char*) clientPacket, sizeof(clientPacket), - node->getActiveSocket()->getAddress(), - node->getActiveSocket()->getPort()); - } - } - - // push forward the next output pointers for any audio buffers we used - for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { - if (node->getLinkedData()) { - ((AudioMixerClientData*) node->getLinkedData())->pushBuffersAfterFrameSend(); - } - } - - // pull any new audio data from nodes off of the network stack - while (nodeList->getNodeSocket().hasPendingDatagrams() && - (receivedBytes = nodeList->getNodeSocket().readDatagram((char*) packetData, MAX_PACKET_SIZE, - nodeSockAddr.getAddressPointer(), - nodeSockAddr.getPortPointer())) && - packetVersionMatch(packetData)) { - if (packetData[0] == PACKET_TYPE_MICROPHONE_AUDIO_NO_ECHO - || packetData[0] == PACKET_TYPE_MICROPHONE_AUDIO_WITH_ECHO - || packetData[0] == PACKET_TYPE_INJECT_AUDIO) { - - QUuid nodeUUID = QUuid::fromRfc4122(QByteArray((char*) packetData + numBytesForPacketHeader(packetData), - NUM_BYTES_RFC4122_UUID)); - - Node* matchingNode = nodeList->nodeWithUUID(nodeUUID); - - if (matchingNode) { - nodeList->updateNodeWithData(matchingNode, nodeSockAddr, packetData, receivedBytes); - - if (!matchingNode->getActiveSocket()) { - // we don't have an active socket for this node, but they're talking to us - // this means they've heard from us and can reply, let's assume public is active - matchingNode->activatePublicSocket(); - } - } - } else { - // let processNodeData handle it. - nodeList->processNodeData(nodeSockAddr, packetData, receivedBytes); - } - } - - if (Logging::shouldSendStats()) { - // send a packet to our logstash instance - - // calculate the percentage value for time elapsed for this send (of the max allowable time) - gettimeofday(&endSendTime, NULL); - - float percentageOfMaxElapsed = ((float) (usecTimestamp(&endSendTime) - usecTimestamp(&beginSendTime)) - / BUFFER_SEND_INTERVAL_USECS) * 100.0f; - - sumFrameTimePercentages += percentageOfMaxElapsed; - - numStatCollections++; - } - - int usecToSleep = usecTimestamp(&startTime) + (++nextFrame * BUFFER_SEND_INTERVAL_USECS) - usecTimestampNow(); - - if (usecToSleep > 0) { - usleep(usecToSleep); - } else { - qDebug("Took too much time, not sleeping!\n"); - } - } + QTimer* mixSendTimer = new QTimer(this); + connect(mixSendTimer, SIGNAL(timeout()), this, SLOT(sendClientMixes())); + mixSendTimer->start(BUFFER_SEND_INTERVAL_MSECS); } \ No newline at end of file diff --git a/assignment-client/src/audio/AudioMixer.h b/assignment-client/src/audio/AudioMixer.h index 4cf0398b9b..d9764170bc 100644 --- a/assignment-client/src/audio/AudioMixer.h +++ b/assignment-client/src/audio/AudioMixer.h @@ -9,6 +9,7 @@ #ifndef __hifi__AudioMixer__ #define __hifi__AudioMixer__ + #include #include @@ -17,11 +18,16 @@ class AvatarAudioRingBuffer; /// Handles assignments of type AudioMixer - mixing streams of audio and re-distributing to various clients. class AudioMixer : public Assignment { + Q_OBJECT public: AudioMixer(const unsigned char* dataBuffer, int numBytes); - +public slots: /// runs the audio mixer void run(); + + void processDatagram(const QByteArray& dataByteArray, const HifiSockAddr& senderSockAddr); +signals: + void finished(); private: /// adds one buffer to the mix for a listening node void addBufferToMixForListeningNodeWithBuffer(PositionalAudioRingBuffer* bufferToAdd, @@ -32,6 +38,9 @@ private: int16_t _clientSamples[BUFFER_LENGTH_SAMPLES_PER_CHANNEL * 2]; +private slots: + void checkInWithDomainServerOrExit(); + void sendClientMixes(); }; #endif /* defined(__hifi__AudioMixer__) */ diff --git a/libraries/shared/src/Assignment.h b/libraries/shared/src/Assignment.h index 47aad34838..68e23e761d 100644 --- a/libraries/shared/src/Assignment.h +++ b/libraries/shared/src/Assignment.h @@ -11,6 +11,7 @@ #include +#include #include #include "NodeList.h" @@ -89,7 +90,7 @@ public: // implement parseData to return 0 so we can be a subclass of NodeData int parseData(unsigned char* sourceBuffer, int numBytes) { return 0; } - /// blocking run of the assignment + /// threaded run of assignment virtual void run(); friend QDebug operator<<(QDebug debug, const Assignment& assignment); diff --git a/libraries/shared/src/HifiSockAddr.h b/libraries/shared/src/HifiSockAddr.h index c5a20896e7..6428453849 100644 --- a/libraries/shared/src/HifiSockAddr.h +++ b/libraries/shared/src/HifiSockAddr.h @@ -45,4 +45,6 @@ private: quint32 getLocalAddress(); +Q_DECLARE_METATYPE(HifiSockAddr) + #endif /* defined(__hifi__HifiSockAddr__) */ diff --git a/libraries/shared/src/NodeData.h b/libraries/shared/src/NodeData.h index 0a2ba3b514..252b03ccc5 100644 --- a/libraries/shared/src/NodeData.h +++ b/libraries/shared/src/NodeData.h @@ -14,7 +14,7 @@ class Node; class NodeData : public QObject { - Q_OBJECT + Q_OBJECT public: NodeData(Node* owningNode = NULL); diff --git a/libraries/shared/src/NodeList.cpp b/libraries/shared/src/NodeList.cpp index 8bd714cd18..b1dfa2ab38 100644 --- a/libraries/shared/src/NodeList.cpp +++ b/libraries/shared/src/NodeList.cpp @@ -75,7 +75,7 @@ NodeList::NodeList(char newOwnerType, unsigned short int newSocketListenPort) : _hasCompletedInitialSTUNFailure(false), _stunRequestsSinceSuccess(0) { - _nodeSocket.bind(QHostAddress::LocalHost, newSocketListenPort); + _nodeSocket.bind(QHostAddress::AnyIPv4, newSocketListenPort); } NodeList::~NodeList() { @@ -339,23 +339,15 @@ void NodeList::sendSTUNRequest() { memcpy(stunRequestPacket + packetIndex, &transactionID, sizeof(transactionID)); // lookup the IP for the STUN server - static QHostInfo stunInfo = QHostInfo::fromName(STUN_SERVER_HOSTNAME); + static HifiSockAddr stunSockAddr(STUN_SERVER_HOSTNAME, STUN_SERVER_PORT); - for (int i = 0; i < stunInfo.addresses().size(); i++) { - if (stunInfo.addresses()[i].protocol() == QAbstractSocket::IPv4Protocol) { - QString stunIPAddress = stunInfo.addresses()[i].toString(); - - if (!_hasCompletedInitialSTUNFailure) { - qDebug("Sending intial stun request to %s\n", stunIPAddress.toLocal8Bit().constData()); - } - - _nodeSocket.writeDatagram((char*) stunRequestPacket, sizeof(stunRequestPacket), - QHostAddress(stunIPAddress), STUN_SERVER_PORT); - - break; - } + if (!_hasCompletedInitialSTUNFailure) { + qDebug("Sending intial stun request to %s\n", stunSockAddr.getAddress().toString().toLocal8Bit().constData()); } + _nodeSocket.writeDatagram((char*) stunRequestPacket, sizeof(stunRequestPacket), + stunSockAddr.getAddress(), stunSockAddr.getPort()); + _stunRequestsSinceSuccess++; if (_stunRequestsSinceSuccess >= NUM_STUN_REQUESTS_BEFORE_FALLBACK) { @@ -800,7 +792,22 @@ void NodeList::killNode(Node* node, bool mustLockNode) { } } -void* removeSilentNodes(void *args) { +void NodeList::removeSilentNodes() { + NodeList* nodeList = NodeList::getInstance(); + + for(NodeList::iterator node = nodeList->begin(); node != nodeList->end(); ++node) { + node->lock(); + + if ((usecTimestampNow() - node->getLastHeardMicrostamp()) > NODE_SILENCE_THRESHOLD_USECS) { + // kill this node, don't lock - we already did it + nodeList->killNode(&(*node), false); + } + + node->unlock(); + } +} + +void* removeSilentNodesAndSleep(void *args) { NodeList* nodeList = (NodeList*) args; uint64_t checkTimeUsecs = 0; int sleepTime = 0; @@ -809,16 +816,7 @@ void* removeSilentNodes(void *args) { checkTimeUsecs = usecTimestampNow(); - for(NodeList::iterator node = nodeList->begin(); node != nodeList->end(); ++node) { - node->lock(); - - if ((usecTimestampNow() - node->getLastHeardMicrostamp()) > NODE_SILENCE_THRESHOLD_USECS) { - // kill this node, don't lock - we already did it - nodeList->killNode(&(*node), false); - } - - node->unlock(); - } + nodeList->removeSilentNodes(); sleepTime = NODE_SILENCE_THRESHOLD_USECS - (usecTimestampNow() - checkTimeUsecs); @@ -841,7 +839,7 @@ void* removeSilentNodes(void *args) { void NodeList::startSilentNodeRemovalThread() { if (!::silentNodeThreadStopFlag) { - pthread_create(&removeSilentNodesThread, NULL, removeSilentNodes, (void*) this); + pthread_create(&removeSilentNodesThread, NULL, removeSilentNodesAndSleep, (void*) this); } else { qDebug("Refusing to start silent node removal thread from previously failed join.\n"); } diff --git a/libraries/shared/src/NodeList.h b/libraries/shared/src/NodeList.h index 0d5d84ecfa..b5d9b1e31e 100644 --- a/libraries/shared/src/NodeList.h +++ b/libraries/shared/src/NodeList.h @@ -60,7 +60,8 @@ public: virtual void domainChanged(QString domain) = 0; }; -class NodeList { +class NodeList : public QObject { + Q_OBJECT public: static NodeList* createInstance(char ownerType, unsigned short int socketListenPort = 0); static NodeList* getInstance(); @@ -79,6 +80,8 @@ public: const QHostAddress& getDomainIP() const { return _domainSockAddr.getAddress(); } void setDomainIPToLocalhost() { _domainSockAddr.setAddress(QHostAddress(INADDR_LOOPBACK)); } + void setDomainSockAddr(const HifiSockAddr& domainSockAddr) { _domainSockAddr = domainSockAddr; } + unsigned short getDomainPort() const { return _domainSockAddr.getPort(); } const QUuid& getOwnerUUID() const { return _ownerUUID; } @@ -98,7 +101,6 @@ public: void setNodeTypesOfInterest(const char* nodeTypesOfInterest, int numNodeTypesOfInterest); - void sendDomainServerCheckIn(); int processDomainServerList(unsigned char *packetData, size_t dataBytes); void setAssignmentServerSocket(const HifiSockAddr& serverSocket) { _assignmentServerSocket = serverSocket; } @@ -141,6 +143,9 @@ public: void possiblyPingInactiveNodes(); const HifiSockAddr* getNodeActiveSocketOrPing(Node* node); +public slots: + void sendDomainServerCheckIn(); + void removeSilentNodes(); private: static NodeList* _sharedInstance; From 113ef1b386e39e45d9f2c4ca45c4441fa3790ea4 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 2 Dec 2013 16:45:13 -0800 Subject: [PATCH 09/31] fix cleanup of finished assignment --- assignment-client/src/AssignmentClient.cpp | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/assignment-client/src/AssignmentClient.cpp b/assignment-client/src/AssignmentClient.cpp index d136d9eb6e..d882afdcae 100644 --- a/assignment-client/src/AssignmentClient.cpp +++ b/assignment-client/src/AssignmentClient.cpp @@ -29,6 +29,9 @@ AssignmentClient::AssignmentClient(int &argc, char **argv, _requestAssignment(Assignment::RequestCommand, requestAssignmentType, requestAssignmentPool), _currentAssignment(NULL) { + // register meta type is required for queued invoke method on Assignment subclasses + qRegisterMetaType("HifiSockAddr"); + // set the logging target to the the CHILD_TARGET_NAME Logging::setTargetName(ASSIGNMENT_CLIENT_TARGET_NAME); @@ -93,9 +96,12 @@ void AssignmentClient::readPendingDatagrams() { QThread *workerThread = new QThread(this); connect(workerThread, SIGNAL(started()), _currentAssignment, SLOT(run())); + + connect(_currentAssignment, SIGNAL(finished()), this, SLOT(assignmentCompleted())); connect(_currentAssignment, SIGNAL(finished()), workerThread, SLOT(quit())); - connect(_currentAssignment, SIGNAL(finished()), _currentAssignment, SLOT(deleteLater())); - connect(_currentAssignment, SIGNAL(finished()), workerThread, SLOT(deleteLater())); + connect(workerThread, SIGNAL(finished()), _currentAssignment, SLOT(deleteLater())); + connect(workerThread, SIGNAL(finished()), workerThread, SLOT(deleteLater())); + _currentAssignment->moveToThread(workerThread); // Starts an event loop, and emits workerThread->started() @@ -105,9 +111,6 @@ void AssignmentClient::readPendingDatagrams() { } } } else if (_currentAssignment) { - - qRegisterMetaType("HifiSockAddr"); - // have the threaded current assignment handle this datagram QMetaObject::invokeMethod(_currentAssignment, "processDatagram", Qt::QueuedConnection, Q_ARG(const QByteArray&, QByteArray((char*) packetData, receivedBytes)), @@ -121,6 +124,9 @@ void AssignmentClient::readPendingDatagrams() { } void AssignmentClient::assignmentCompleted() { + // reset the logging target to the the CHILD_TARGET_NAME + Logging::setTargetName(ASSIGNMENT_CLIENT_TARGET_NAME); + qDebug("Assignment finished or never started - waiting for new assignment\n"); // the _currentAssignment is being deleted, set our pointer to NULL @@ -131,7 +137,4 @@ void AssignmentClient::assignmentCompleted() { // reset our NodeList by switching back to unassigned and clearing the list nodeList->setOwnerType(NODE_TYPE_UNASSIGNED); nodeList->reset(); - - // reset the logging target to the the CHILD_TARGET_NAME - Logging::setTargetName(ASSIGNMENT_CLIENT_TARGET_NAME); } From 330eff72cee5dbe34f6ffbdcee0808f16a805051 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 2 Dec 2013 17:18:07 -0800 Subject: [PATCH 10/31] repair usage of DS as STUN server --- assignment-client/src/AssignmentClient.cpp | 2 +- assignment-client/src/audio/AudioMixer.cpp | 2 +- assignment-client/src/audio/AudioMixer.h | 4 ++-- domain-server/src/DomainServer.cpp | 6 +++--- interface/src/PairingHandler.cpp | 2 +- libraries/shared/src/HifiSockAddr.cpp | 17 +++++++++-------- libraries/shared/src/HifiSockAddr.h | 2 +- libraries/shared/src/Node.cpp | 2 +- libraries/shared/src/NodeList.cpp | 7 +++++-- 9 files changed, 24 insertions(+), 20 deletions(-) diff --git a/assignment-client/src/AssignmentClient.cpp b/assignment-client/src/AssignmentClient.cpp index d882afdcae..6b2b27730d 100644 --- a/assignment-client/src/AssignmentClient.cpp +++ b/assignment-client/src/AssignmentClient.cpp @@ -95,7 +95,7 @@ void AssignmentClient::readPendingDatagrams() { // start the deployed assignment QThread *workerThread = new QThread(this); - connect(workerThread, SIGNAL(started()), _currentAssignment, SLOT(run())); + connect(workerThread, SIGNAL(started()), _currentAssignment, SLOT(setup())); connect(_currentAssignment, SIGNAL(finished()), this, SLOT(assignmentCompleted())); connect(_currentAssignment, SIGNAL(finished()), workerThread, SLOT(quit())); diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 451904bb48..94bd787140 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -293,7 +293,7 @@ void AudioMixer::sendClientMixes() { } -void AudioMixer::run() { +void AudioMixer::setup() { // change the logging target name while this is running Logging::setTargetName(AUDIO_MIXER_LOGGING_TARGET_NAME); diff --git a/assignment-client/src/audio/AudioMixer.h b/assignment-client/src/audio/AudioMixer.h index d9764170bc..f2fbd04373 100644 --- a/assignment-client/src/audio/AudioMixer.h +++ b/assignment-client/src/audio/AudioMixer.h @@ -22,8 +22,8 @@ class AudioMixer : public Assignment { public: AudioMixer(const unsigned char* dataBuffer, int numBytes); public slots: - /// runs the audio mixer - void run(); + /// performs setup for the audio mixer + void setup(); void processDatagram(const QByteArray& dataByteArray, const HifiSockAddr& senderSockAddr); signals: diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 175118ef7d..b10006e6cc 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -628,16 +628,16 @@ int DomainServer::run() { int numBytesPrivateSocket = HifiSockAddr::unpackSockAddr(packetData + packetIndex, nodePublicAddress); packetIndex += numBytesPrivateSocket; - if (nodePublicAddress.getAddress().isNull() == 0) { + if (nodePublicAddress.getAddress().isNull()) { // this node wants to use us its STUN server // so set the node public address to whatever we perceive the public address to be - nodePublicAddress.setAddress(senderAddress); - // if the sender is on our box then leave its public address to 0 so that // other users attempt to reach it on the same address they have for the domain-server if (senderAddress.isLoopback()) { nodePublicAddress.setAddress(QHostAddress()); + } else { + nodePublicAddress.setAddress(senderAddress); } } diff --git a/interface/src/PairingHandler.cpp b/interface/src/PairingHandler.cpp index 56d7642640..718a8c7dc8 100644 --- a/interface/src/PairingHandler.cpp +++ b/interface/src/PairingHandler.cpp @@ -37,7 +37,7 @@ void PairingHandler::sendPairRequest() { NodeList* nodeList = NodeList::getInstance(); // use the getLocalAddress helper to get this client's listening address - quint32 localAddress = getLocalAddress(); + quint32 localAddress = htonl(getHostOrderLocalAddress()); char pairPacket[24] = {}; sprintf(pairPacket, "Find %d.%d.%d.%d:%hu", diff --git a/libraries/shared/src/HifiSockAddr.cpp b/libraries/shared/src/HifiSockAddr.cpp index 66ae200026..0fdc8919ed 100644 --- a/libraries/shared/src/HifiSockAddr.cpp +++ b/libraries/shared/src/HifiSockAddr.cpp @@ -12,7 +12,7 @@ #include HifiSockAddr::HifiSockAddr() : - _address(QHostAddress::Null), + _address(), _port(0) { @@ -55,15 +55,16 @@ void HifiSockAddr::swap(HifiSockAddr& otherSockAddr) { } int HifiSockAddr::packSockAddr(unsigned char* packetData, const HifiSockAddr& packSockAddr) { - unsigned int addressToPack = packSockAddr._address.toIPv4Address(); - memcpy(packetData, &addressToPack, sizeof(packSockAddr._address.toIPv4Address())); - memcpy(packetData, &packSockAddr._port, sizeof(packSockAddr._port)); + quint32 addressToPack = packSockAddr._address.isNull() ? 0 : packSockAddr._address.toIPv4Address(); + memcpy(packetData, &addressToPack, sizeof(addressToPack)); + memcpy(packetData + sizeof(addressToPack), &packSockAddr._port, sizeof(packSockAddr._port)); return sizeof(addressToPack) + sizeof(packSockAddr._port); } int HifiSockAddr::unpackSockAddr(const unsigned char* packetData, HifiSockAddr& unpackDestSockAddr) { - unpackDestSockAddr._address = QHostAddress(*((quint32*) packetData)); + quint32* address = (quint32*) packetData; + unpackDestSockAddr._address = *address == 0 ? QHostAddress() : QHostAddress(*address); unpackDestSockAddr._port = *((quint16*) (packetData + sizeof(quint32))); return sizeof(quint32) + sizeof(quint16); @@ -74,11 +75,11 @@ bool HifiSockAddr::operator==(const HifiSockAddr &rhsSockAddr) const { } QDebug operator<<(QDebug debug, const HifiSockAddr &hifiSockAddr) { - debug.nospace() << hifiSockAddr._address.toString() << ":" << hifiSockAddr._port; + debug.nospace() << hifiSockAddr._address.toString().toLocal8Bit().constData() << ":" << hifiSockAddr._port; return debug; } -quint32 getLocalAddress() { +quint32 getHostOrderLocalAddress() { static int localAddress = 0; @@ -95,7 +96,7 @@ quint32 getLocalAddress() { qDebug("Node's local address is %s\n", entry.ip().toString().toLocal8Bit().constData()); // set our localAddress and break out - localAddress = htonl(entry.ip().toIPv4Address()); + localAddress = entry.ip().toIPv4Address(); break; } } diff --git a/libraries/shared/src/HifiSockAddr.h b/libraries/shared/src/HifiSockAddr.h index 6428453849..f11492805f 100644 --- a/libraries/shared/src/HifiSockAddr.h +++ b/libraries/shared/src/HifiSockAddr.h @@ -43,7 +43,7 @@ private: quint16 _port; }; -quint32 getLocalAddress(); +quint32 getHostOrderLocalAddress(); Q_DECLARE_METATYPE(HifiSockAddr) diff --git a/libraries/shared/src/Node.cpp b/libraries/shared/src/Node.cpp index cc82677f9a..bcaf64f9c6 100644 --- a/libraries/shared/src/Node.cpp +++ b/libraries/shared/src/Node.cpp @@ -136,6 +136,6 @@ float Node::getAverageKilobitsPerSecond() { QDebug operator<<(QDebug debug, const Node &node) { debug.nospace() << node.getTypeName() << " (" << node.getType() << ")"; debug << " " << node.getUUID().toString().toLocal8Bit().constData() << " "; - debug.nospace() << node.getLocalSocket() << "/" << node.getPublicSocket(); + debug.nospace() << node.getPublicSocket() << "/" << node.getLocalSocket(); return debug.nospace(); } diff --git a/libraries/shared/src/NodeList.cpp b/libraries/shared/src/NodeList.cpp index b1dfa2ab38..16b55bd1db 100644 --- a/libraries/shared/src/NodeList.cpp +++ b/libraries/shared/src/NodeList.cpp @@ -76,6 +76,7 @@ NodeList::NodeList(char newOwnerType, unsigned short int newSocketListenPort) : _stunRequestsSinceSuccess(0) { _nodeSocket.bind(QHostAddress::AnyIPv4, newSocketListenPort); + qDebug() << "NodeList socket is listening on" << _nodeSocket.localPort() << "\n"; } NodeList::~NodeList() { @@ -361,7 +362,8 @@ void NodeList::sendSTUNRequest() { } // reset the public address and port - _publicSockAddr = HifiSockAddr(); + // use 0 so the DS knows to act as out STUN server + _publicSockAddr = HifiSockAddr(QHostAddress(), _nodeSocket.localPort()); } } @@ -539,7 +541,8 @@ void NodeList::sendDomainServerCheckIn() { // pack our local address to send to domain-server packetPosition += HifiSockAddr::packSockAddr(checkInPacket + (packetPosition - checkInPacket), - HifiSockAddr(_nodeSocket.localAddress(), _nodeSocket.localPort())); + HifiSockAddr(QHostAddress(getHostOrderLocalAddress()), + _nodeSocket.localPort())); // add the number of bytes for node types of interest *(packetPosition++) = numBytesNodesOfInterest; From a84e97c54acfe32d3982dc39907ecec9818db2e5 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Tue, 3 Dec 2013 08:29:17 -0800 Subject: [PATCH 11/31] Removed obsolete HandControl class, files --- interface/src/Application.cpp | 33 +++++++--- interface/src/Application.h | 15 +++-- interface/src/avatar/Hand.cpp | 71 ++++++++++++++++++--- interface/src/avatar/Hand.h | 1 + interface/src/avatar/HandControl.cpp | 92 ---------------------------- interface/src/avatar/HandControl.h | 41 ------------- libraries/avatars/src/HandData.cpp | 5 +- libraries/avatars/src/HandData.h | 11 ++++ 8 files changed, 114 insertions(+), 155 deletions(-) delete mode 100644 interface/src/avatar/HandControl.cpp delete mode 100644 interface/src/avatar/HandControl.h diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index b531473a1c..07996dd7db 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -126,6 +126,7 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : _mouseVoxelScale(1.0f / 1024.0f), _mouseVoxelScaleInitialized(false), _justEditedVoxel(false), + _isHighlightVoxel(false), _nudgeStarted(false), _lookingAlongX(false), _lookingAwayFromOrigin(true), @@ -1765,8 +1766,6 @@ void Application::init() { _voxelShader.init(); _pointShader.init(); - _handControl.setScreenDimensions(_glWidget->width(), _glWidget->height()); - _headMouseX = _mouseX = _glWidget->width() / 2; _headMouseY = _mouseY = _glWidget->height() / 2; QCursor::setPos(_headMouseX, _headMouseY); @@ -1991,6 +1990,24 @@ void Application::renderFollowIndicator() { } } +void Application::renderHighlightVoxel(VoxelDetail voxel) { + glDisable(GL_LIGHTING); + glPushMatrix(); + glScalef(TREE_SCALE, TREE_SCALE, TREE_SCALE); + //printf("Render: %.6f,%.6f,%.6f %.8f\n", voxel.x, voxel.y, voxel.z, + // voxel.s); + const float EDGE_EXPAND = 1.01f; + //glColor3ub(voxel.red + 128, voxel.green + 128, voxel.blue + 128); + glColor3ub(255, 0, 0); + + glTranslatef(voxel.x + voxel.s * 0.5f, + voxel.y + voxel.s * 0.5f, + voxel.z + voxel.s * 0.5f); + glLineWidth(4.0f); + glutWireCube(_mouseVoxel.s * EDGE_EXPAND); + glPopMatrix(); +} + void Application::updateAvatars(float deltaTime, glm::vec3 mouseRayOrigin, glm::vec3 mouseRayDirection) { bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); PerformanceWarning warn(showWarnings, "Application::updateAvatars()"); @@ -2236,11 +2253,6 @@ void Application::updateHandAndTouch(float deltaTime) { bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); PerformanceWarning warn(showWarnings, "Application::updateHandAndTouch()"); - // walking triggers the handControl to stop - if (_myAvatar.getMode() == AVATAR_MODE_WALKING) { - _handControl.stop(); - } - // Update from Touch if (_isTouchPressed) { float TOUCH_YAW_SCALE = -0.25f; @@ -3025,6 +3037,11 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { // restore default, white specular glMaterialfv(GL_FRONT, GL_SPECULAR, WHITE_SPECULAR_COLOR); + // Render the highlighted voxel + if (_isHighlightVoxel) { + renderHighlightVoxel(_highlightVoxel); + } + // indicate what we'll be adding/removing in mouse mode, if anything if (_mouseVoxel.s != 0 && whichCamera.getMode() != CAMERA_MODE_MIRROR) { PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), @@ -3048,7 +3065,7 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { } else { renderMouseVoxelGrid(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); } - + if (Menu::getInstance()->isOptionChecked(MenuOption::VoxelAddMode)) { // use a contrasting color so that we can see what we're doing glColor3ub(_mouseVoxel.red + 128, _mouseVoxel.green + 128, _mouseVoxel.blue + 128); diff --git a/interface/src/Application.h b/interface/src/Application.h index 3e798c10e8..26a82a4c77 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -47,7 +47,6 @@ #include "avatar/Avatar.h" #include "avatar/MyAvatar.h" #include "avatar/Profile.h" -#include "avatar/HandControl.h" #include "devices/Faceshift.h" #include "devices/SerialInterface.h" #include "devices/SixenseManager.h" @@ -188,6 +187,10 @@ public: glm::vec2 getViewportDimensions() const{ return glm::vec2(_glWidget->width(),_glWidget->height()); } NodeToJurisdictionMap& getVoxelServerJurisdictions() { return _voxelServerJurisdictions; } void pasteVoxelsToOctalCode(const unsigned char* octalCodeDestination); + + /// set a voxel which is to be rendered with a highlight + void setHighlightVoxel(const VoxelDetail& highlightVoxel) { _highlightVoxel = highlightVoxel; } + void setIsHighlightVoxel(bool isHighlightVoxel) { _isHighlightVoxel = isHighlightVoxel; } public slots: void sendAvatarFaceVideoMessage(int frameCount, const QByteArray& data); @@ -231,6 +234,7 @@ private slots: void shrinkMirrorView(); void resetSensors(); + private: void resetCamerasOnResizeGL(Camera& camera, int width, int height); void updateProjectionMatrix(); @@ -272,9 +276,11 @@ private: Avatar* findLookatTargetAvatar(const glm::vec3& mouseRayOrigin, const glm::vec3& mouseRayDirection, glm::vec3& eyePosition, QUuid &nodeUUID); bool isLookingAtMyAvatar(Avatar* avatar); - + void renderLookatIndicator(glm::vec3 pointOfInterest); void renderFollowIndicator(); + void renderHighlightVoxel(VoxelDetail voxel); + void updateAvatar(float deltaTime); void updateAvatars(float deltaTime, glm::vec3 mouseRayOrigin, glm::vec3 mouseRayDirection); void queryVoxels(); @@ -371,8 +377,6 @@ private: int _headMouseX, _headMouseY; - HandControl _handControl; - int _mouseX; int _mouseY; int _mouseDragStartedX; @@ -405,6 +409,9 @@ private: glm::vec3 _lastMouseVoxelPos; // the position of the last mouse voxel edit bool _justEditedVoxel; // set when we've just added/deleted/colored a voxel + VoxelDetail _highlightVoxel; + bool _isHighlightVoxel; + VoxelDetail _nudgeVoxel; // details of the voxel to be nudged bool _nudgeStarted; bool _lookingAlongX; diff --git a/interface/src/avatar/Hand.cpp b/interface/src/avatar/Hand.cpp index f733a40c9f..d17c30d749 100755 --- a/interface/src/avatar/Hand.cpp +++ b/interface/src/avatar/Hand.cpp @@ -24,7 +24,7 @@ Hand::Hand(Avatar* owningAvatar) : _raveGloveInitialized(false), _owningAvatar(owningAvatar), _renderAlpha(1.0), - _ballColor(0.0, 0.0, 0.4) + _ballColor(0.0, 0.0, 0.4) { // initialize all finger particle emitters with an invalid id as default for (int f = 0; f< NUM_FINGERS; f ++ ) { @@ -67,25 +67,72 @@ void Hand::simulate(float deltaTime, bool isMine) { for (size_t i = 0; i < getNumPalms(); ++i) { PalmData& palm = getPalms()[i]; if (palm.isActive()) { + glm::vec3 palmPosition = palm.getPosition(); FingerData& finger = palm.getFingers()[0]; - glm::vec3 newVoxelPosition = finger.getTipPosition(); + glm::vec3 fingerTipPosition = finger.getTipPosition(); if (palm.getControllerButtons() & BUTTON_1) { - if (glm::length(newVoxelPosition - _lastFingerAddVoxel) > (FINGERTIP_VOXEL_SIZE / 2.f)) { + if (glm::length(fingerTipPosition - _lastFingerAddVoxel) > (FINGERTIP_VOXEL_SIZE / 2.f)) { QColor paintColor = Menu::getInstance()->getActionForOption(MenuOption::VoxelPaintColor)->data().value(); - Application::getInstance()->makeVoxel(newVoxelPosition, + Application::getInstance()->makeVoxel(fingerTipPosition, FINGERTIP_VOXEL_SIZE, paintColor.red(), paintColor.green(), paintColor.blue(), true); - _lastFingerAddVoxel = newVoxelPosition; + _lastFingerAddVoxel = fingerTipPosition; } } else if (palm.getControllerButtons() & BUTTON_2) { - if (glm::length(newVoxelPosition - _lastFingerDeleteVoxel) > (FINGERTIP_VOXEL_SIZE / 2.f)) { - Application::getInstance()->removeVoxel(newVoxelPosition, FINGERTIP_VOXEL_SIZE); - _lastFingerDeleteVoxel = newVoxelPosition; + if (glm::length(fingerTipPosition - _lastFingerDeleteVoxel) > (FINGERTIP_VOXEL_SIZE / 2.f)) { + Application::getInstance()->removeVoxel(fingerTipPosition, FINGERTIP_VOXEL_SIZE); + _lastFingerDeleteVoxel = fingerTipPosition; } } + // Check if the finger is intersecting with a voxel in the client voxel tree + VoxelNode* fingerNode = Application::getInstance()->getVoxels()->getVoxelAt(fingerTipPosition.x / TREE_SCALE, + fingerTipPosition.y / TREE_SCALE, + fingerTipPosition.z / TREE_SCALE, + FINGERTIP_VOXEL_SIZE / TREE_SCALE); + if (fingerNode) { + finger.setIsTouchingVoxel(true); + glm::vec3 corner = fingerNode->getCorner(); + glm::vec3 storedCorner = finger.getFingerVoxelPosition(); + printf("corner: %.3f, %.3f, %.3f ", corner.x, corner.y, corner.z); + printf("stored corner: %.3f, %.3f, %.3f\n", storedCorner.x, storedCorner.y, storedCorner.z); + if (finger.getIsTouchingVoxel()) printf("Touching! %f.3", randFloat()); + if (glm::length(fingerNode->getCorner() - finger.getFingerVoxelPosition()) > EPSILON) { + printf("diff = %.9f\n", glm::length(fingerNode->getCorner() - finger.getFingerVoxelPosition())); + finger.setFingerVoxelPosition(fingerNode->getCorner()); + finger.setFingerVoxelScale(fingerNode->getScale()); + printf("touching voxel scale, %0.4f\n", fingerNode->getScale() * TREE_SCALE); + printVector(glm::vec3(fingerNode->getCorner() * (float)TREE_SCALE)); + } + /* + if ((currentFingerVoxel.x != _fingerVoxel.x) || + (currentFingerVoxel.y != _fingerVoxel.y) || + (currentFingerVoxel.z != _fingerVoxel.z) || + (currentFingerVoxel.s != _fingerVoxel.s) || + (currentFingerVoxel.red != _fingerVoxel.red) || + (currentFingerVoxel.green != _fingerVoxel.green) || + (currentFingerVoxel.blue != _fingerVoxel.blue)) { + memcpy(&_fingerVoxel, ¤tFingerVoxel, sizeof(VoxelDetail)); + _fingerIsOnVoxel = true; + Application::getInstance()->setHighlightVoxel(currentFingerVoxel); + Application::getInstance()->setIsHighlightVoxel(true); + printf("Moved onto a voxel %.2f, %.2f, %.2f s %.2f\n", + currentFingerVoxel.x * TREE_SCALE, + currentFingerVoxel.y * TREE_SCALE, + currentFingerVoxel.z * TREE_SCALE, + currentFingerVoxel.s * TREE_SCALE); + // If desired, make a sound + Application::getInstance()->getAudio()->startCollisionSound(1.0, 7040 * currentFingerVoxel.s * TREE_SCALE, 0.0, 0.999f, false); + } + */ + } else if (finger.getIsTouchingVoxel()) { + // Just moved off a voxel, change back it's color + printf("Moved out of voxel!\n"); + finger.setIsTouchingVoxel(false); + Application::getInstance()->setIsHighlightVoxel(false); + } } } } @@ -113,6 +160,7 @@ void Hand::calculateGeometry() { ball.radius = standardBallRadius; ball.touchForce = 0.0; ball.isCollidable = true; + ball.isColliding = false; } } } @@ -134,6 +182,7 @@ void Hand::calculateGeometry() { ball.radius = standardBallRadius; ball.touchForce = 0.0; ball.isCollidable = true; + ball.isColliding = false; } } } @@ -299,7 +348,11 @@ void Hand::renderLeapHands() { // Draw the leap balls for (size_t i = 0; i < _leapFingerTipBalls.size(); i++) { if (alpha > 0.0f) { - glColor4f(handColor.r, handColor.g, handColor.b, alpha); + if (_leapFingerTipBalls[i].isColliding) { + glColor4f(handColor.r, 0, 0, alpha); + } else { + glColor4f(handColor.r, handColor.g, handColor.b, alpha); + } glPushMatrix(); glTranslatef(_leapFingerTipBalls[i].position.x, _leapFingerTipBalls[i].position.y, _leapFingerTipBalls[i].position.z); diff --git a/interface/src/avatar/Hand.h b/interface/src/avatar/Hand.h index aea03f4cc1..5e8acdbaa6 100755 --- a/interface/src/avatar/Hand.h +++ b/interface/src/avatar/Hand.h @@ -45,6 +45,7 @@ public: glm::vec3 velocity; // the velocity of the ball float radius; // the radius of the ball bool isCollidable; // whether or not the ball responds to collisions + bool isColliding; // ball is currently colliding float touchForce; // a scalar determining the amount that the cursor (or hand) is penetrating the ball }; diff --git a/interface/src/avatar/HandControl.cpp b/interface/src/avatar/HandControl.cpp deleted file mode 100644 index 596f971bd2..0000000000 --- a/interface/src/avatar/HandControl.cpp +++ /dev/null @@ -1,92 +0,0 @@ -// -// HandControl.cpp -// interface -// -// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. -// - -#include "HandControl.h" - -// this class takes mouse movements normalized within the screen -// dimensions and uses those to determine avatar hand movements, as well -// as states for ramping up and ramping down the amplitude of such movements. -// -// This class might expand to accommodate 3D input devices -// - -HandControl::HandControl() { - - _enabled = false; - _width = 0; - _height = 0; - _startX = 0; - _startY = 0; - _x = 0; - _y = 0; - _lastX = 0; - _lastY = 0; - _velocityX = 0; - _velocityY = 0; - _rampUpRate = 0.05; - _rampDownRate = 0.02; - _envelope = 0.0f; -} - -void HandControl::setScreenDimensions(int width, int height) { - _width = width; - _height = height; - _startX = _width / 2; - _startY = _height / 2; -} - -void HandControl::update(int x, int y) { - _lastX = _x; - _lastY = _y; - _x = x; - _y = y; - _velocityX = _x - _lastX; - _velocityY = _y - _lastY; - - // if the mouse is moving, ramp up the envelope to increase amplitude of hand movement... - if ((_velocityX != 0) - || (_velocityY != 0)) { - _enabled = true; - if (_envelope < 1.0) { - _envelope += _rampUpRate; - if (_envelope >= 1.0) { - _envelope = 1.0; - } - } - } - - // if not enabled ramp down the envelope to decrease amplitude of hand movement... - if (! _enabled) { - if (_envelope > 0.0) { - _envelope -= _rampDownRate; - if (_envelope <= 0.0) { - _startX = _width / 2; - _startY = _height / 2; - _envelope = 0.0; - } - } - } - - _leftRight = 0.0; - _downUp = 0.0; - _backFront = 0.0; - - // if envelope is greater than zero, apply mouse movement to values to be output - if (_envelope > 0.0) { - _leftRight += ((_x - _startX) / (float)_width ) * _envelope; - _downUp += ((_y - _startY) / (float)_height) * _envelope; - } -} - -glm::vec3 HandControl::getValues() { - return glm::vec3(_leftRight, _downUp, _backFront); -} - -void HandControl::stop() { - _enabled = false; -} - diff --git a/interface/src/avatar/HandControl.h b/interface/src/avatar/HandControl.h deleted file mode 100644 index b2abef48bb..0000000000 --- a/interface/src/avatar/HandControl.h +++ /dev/null @@ -1,41 +0,0 @@ -// -// HandControl.h -// interface -// -// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. -// - -#ifndef __interface__HandControl__ -#define __interface__HandControl__ - -#include - -class HandControl { -public: - HandControl(); - void setScreenDimensions(int width, int height); - void update( int x, int y ); - glm::vec3 getValues(); - void stop(); - -private: - bool _enabled; - int _width; - int _height; - int _startX; - int _startY; - int _x; - int _y; - int _lastX; - int _lastY; - int _velocityX; - int _velocityY; - float _rampUpRate; - float _rampDownRate; - float _envelope; - float _leftRight; - float _downUp; - float _backFront; -}; - -#endif diff --git a/libraries/avatars/src/HandData.cpp b/libraries/avatars/src/HandData.cpp index cfa43725b8..06a30f9e38 100644 --- a/libraries/avatars/src/HandData.cpp +++ b/libraries/avatars/src/HandData.cpp @@ -56,7 +56,10 @@ _isActive(false), _leapID(LEAPID_INVALID), _numFramesWithoutData(0), _owningPalmData(owningPalmData), -_owningHandData(owningHandData) +_owningHandData(owningHandData), +_isTouchingVoxel(false), +_fingerVoxelPosition(), +_fingerVoxelScale(0) { const int standardTrailLength = 10; setTrailLength(standardTrailLength); diff --git a/libraries/avatars/src/HandData.h b/libraries/avatars/src/HandData.h index b8a06d53ad..c072d9afb2 100755 --- a/libraries/avatars/src/HandData.h +++ b/libraries/avatars/src/HandData.h @@ -119,6 +119,13 @@ public: void incrementFramesWithoutData() { _numFramesWithoutData++; } void resetFramesWithoutData() { _numFramesWithoutData = 0; } int getFramesWithoutData() const { return _numFramesWithoutData; } + + void setIsTouchingVoxel(bool isTouchingVoxel) { _isTouchingVoxel = isTouchingVoxel; } + bool getIsTouchingVoxel() { return _isTouchingVoxel; } + void setFingerVoxelPosition(const glm::vec3& fingerVoxelPosition) { _fingerVoxelPosition = fingerVoxelPosition; } + const glm::vec3& getFingerVoxelPosition() const { return _fingerVoxelPosition; } + void setFingerVoxelScale(float fingerVoxelScale) { _fingerVoxelScale = fingerVoxelScale; } + float getFingerVoxelScale() { return _fingerVoxelScale; } private: glm::vec3 _tipRawPosition; @@ -131,6 +138,10 @@ private: int _tipTrailCurrentValidLength; PalmData* _owningPalmData; HandData* _owningHandData; + + bool _isTouchingVoxel; + glm::vec3 _fingerVoxelPosition; + float _fingerVoxelScale; }; class PalmData { From 02732e9a2e69bd4bbdec810b2f3150cdf4469024 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 3 Dec 2013 10:03:56 -0800 Subject: [PATCH 12/31] cleanup memory leaks and timing on assignment threading --- assignment-client/src/AssignmentClient.cpp | 5 +- assignment-client/src/audio/AudioMixer.cpp | 113 +++++++++++++-------- assignment-client/src/audio/AudioMixer.h | 5 +- 3 files changed, 78 insertions(+), 45 deletions(-) diff --git a/assignment-client/src/AssignmentClient.cpp b/assignment-client/src/AssignmentClient.cpp index 6b2b27730d..650b88c47b 100644 --- a/assignment-client/src/AssignmentClient.cpp +++ b/assignment-client/src/AssignmentClient.cpp @@ -93,13 +93,13 @@ void AssignmentClient::readPendingDatagrams() { nodeList->getDomainIP().toString().toStdString().c_str()); // start the deployed assignment - QThread *workerThread = new QThread(this); + QThread* workerThread = new QThread(this); connect(workerThread, SIGNAL(started()), _currentAssignment, SLOT(setup())); connect(_currentAssignment, SIGNAL(finished()), this, SLOT(assignmentCompleted())); connect(_currentAssignment, SIGNAL(finished()), workerThread, SLOT(quit())); - connect(workerThread, SIGNAL(finished()), _currentAssignment, SLOT(deleteLater())); + connect(_currentAssignment, SIGNAL(finished()), _currentAssignment, SLOT(deleteLater())); connect(workerThread, SIGNAL(finished()), workerThread, SLOT(deleteLater())); _currentAssignment->moveToThread(workerThread); @@ -129,7 +129,6 @@ void AssignmentClient::assignmentCompleted() { qDebug("Assignment finished or never started - waiting for new assignment\n"); - // the _currentAssignment is being deleted, set our pointer to NULL _currentAssignment = NULL; NodeList* nodeList = NodeList::getInstance(); diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 94bd787140..5e4e2596b4 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -32,6 +32,7 @@ #include #include +#include #include #include @@ -53,7 +54,7 @@ const short JITTER_BUFFER_MSECS = 12; const short JITTER_BUFFER_SAMPLES = JITTER_BUFFER_MSECS * (SAMPLE_RATE / 1000.0); -const unsigned int BUFFER_SEND_INTERVAL_MSECS = floorf((BUFFER_LENGTH_SAMPLES_PER_CHANNEL / SAMPLE_RATE) * 1000); +const unsigned int BUFFER_SEND_INTERVAL_USECS = floorf((BUFFER_LENGTH_SAMPLES_PER_CHANNEL / SAMPLE_RATE) * 1000 * 1000); const int MAX_SAMPLE_VALUE = std::numeric_limits::max(); const int MIN_SAMPLE_VALUE = std::numeric_limits::min(); @@ -66,7 +67,10 @@ void attachNewBufferToNode(Node *newNode) { } } -AudioMixer::AudioMixer(const unsigned char* dataBuffer, int numBytes) : Assignment(dataBuffer, numBytes) { +AudioMixer::AudioMixer(const unsigned char* dataBuffer, int numBytes) : + Assignment(dataBuffer, numBytes), + _isFinished(false) +{ } @@ -247,51 +251,20 @@ void AudioMixer::processDatagram(const QByteArray& dataByteArray, const HifiSock } } +timeval lastCall = {}; void AudioMixer::checkInWithDomainServerOrExit() { + qDebug() << (usecTimestampNow() - usecTimestamp(&lastCall)) << "\n"; + gettimeofday(&lastCall, NULL); + if (NodeList::getInstance()->getNumNoReplyDomainCheckIns() == MAX_SILENT_DOMAIN_SERVER_CHECK_INS) { + _isFinished = true; emit finished(); } else { NodeList::getInstance()->sendDomainServerCheckIn(); } } -void AudioMixer::sendClientMixes() { - NodeList* nodeList = NodeList::getInstance(); - - // get the NodeList to ping any inactive nodes, for hole punching - nodeList->possiblyPingInactiveNodes(); - - int numBytesPacketHeader = numBytesForPacketHeader((unsigned char*) &PACKET_TYPE_MIXED_AUDIO); - unsigned char clientPacket[BUFFER_LENGTH_BYTES_STEREO + numBytesPacketHeader]; - populateTypeAndVersion(clientPacket, PACKET_TYPE_MIXED_AUDIO); - - for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { - if (node->getLinkedData()) { - ((AudioMixerClientData*) node->getLinkedData())->checkBuffersBeforeFrameSend(JITTER_BUFFER_SAMPLES); - } - } - - for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { - if (node->getType() == NODE_TYPE_AGENT && node->getActiveSocket() && node->getLinkedData() - && ((AudioMixerClientData*) node->getLinkedData())->getAvatarAudioRingBuffer()) { - prepareMixForListeningNode(&(*node)); - - memcpy(clientPacket + numBytesPacketHeader, _clientSamples, sizeof(_clientSamples)); - nodeList->getNodeSocket().writeDatagram((char*) clientPacket, sizeof(clientPacket), - node->getActiveSocket()->getAddress(), - node->getActiveSocket()->getPort()); - } - } - - // push forward the next output pointers for any audio buffers we used - for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { - if (node->getLinkedData()) { - ((AudioMixerClientData*) node->getLinkedData())->pushBuffersAfterFrameSend(); - } - } -} - void AudioMixer::setup() { // change the logging target name while this is running @@ -313,7 +286,65 @@ void AudioMixer::setup() { connect(silentNodeTimer, SIGNAL(timeout()), nodeList, SLOT(removeSilentNodes())); silentNodeTimer->start(NODE_SILENCE_THRESHOLD_USECS / 1000); - QTimer* mixSendTimer = new QTimer(this); - connect(mixSendTimer, SIGNAL(timeout()), this, SLOT(sendClientMixes())); - mixSendTimer->start(BUFFER_SEND_INTERVAL_MSECS); + run(); +} + +void AudioMixer::run() { + + NodeList* nodeList = NodeList::getInstance(); + + int nextFrame = 0; + timeval startTime; + + gettimeofday(&startTime, NULL); + + int numBytesPacketHeader = numBytesForPacketHeader((unsigned char*) &PACKET_TYPE_MIXED_AUDIO); + unsigned char clientPacket[BUFFER_LENGTH_BYTES_STEREO + numBytesPacketHeader]; + populateTypeAndVersion(clientPacket, PACKET_TYPE_MIXED_AUDIO); + + while (!_isFinished) { + + // get the NodeList to ping any inactive nodes, for hole punching + nodeList->possiblyPingInactiveNodes(); + + int numBytesPacketHeader = numBytesForPacketHeader((unsigned char*) &PACKET_TYPE_MIXED_AUDIO); + unsigned char clientPacket[BUFFER_LENGTH_BYTES_STEREO + numBytesPacketHeader]; + populateTypeAndVersion(clientPacket, PACKET_TYPE_MIXED_AUDIO); + + for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { + if (node->getLinkedData()) { + ((AudioMixerClientData*) node->getLinkedData())->checkBuffersBeforeFrameSend(JITTER_BUFFER_SAMPLES); + } + } + + for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { + if (node->getType() == NODE_TYPE_AGENT && node->getActiveSocket() && node->getLinkedData() + && ((AudioMixerClientData*) node->getLinkedData())->getAvatarAudioRingBuffer()) { + prepareMixForListeningNode(&(*node)); + + memcpy(clientPacket + numBytesPacketHeader, _clientSamples, sizeof(_clientSamples)); + nodeList->getNodeSocket().writeDatagram((char*) clientPacket, sizeof(clientPacket), + node->getActiveSocket()->getAddress(), + node->getActiveSocket()->getPort()); + } + } + + // push forward the next output pointers for any audio buffers we used + for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { + if (node->getLinkedData()) { + ((AudioMixerClientData*) node->getLinkedData())->pushBuffersAfterFrameSend(); + } + } + + QCoreApplication::processEvents(); + + int usecToSleep = usecTimestamp(&startTime) + (++nextFrame * BUFFER_SEND_INTERVAL_USECS) - usecTimestampNow(); + + if (usecToSleep > 0) { + usleep(usecToSleep); + } else { + qDebug("Took too much time, not sleeping!\n"); + } + + } } \ No newline at end of file diff --git a/assignment-client/src/audio/AudioMixer.h b/assignment-client/src/audio/AudioMixer.h index f2fbd04373..b38d553564 100644 --- a/assignment-client/src/audio/AudioMixer.h +++ b/assignment-client/src/audio/AudioMixer.h @@ -25,6 +25,9 @@ public slots: /// performs setup for the audio mixer void setup(); + /// performs run of audio mixer + void run(); + void processDatagram(const QByteArray& dataByteArray, const HifiSockAddr& senderSockAddr); signals: void finished(); @@ -38,9 +41,9 @@ private: int16_t _clientSamples[BUFFER_LENGTH_SAMPLES_PER_CHANNEL * 2]; + bool _isFinished; private slots: void checkInWithDomainServerOrExit(); - void sendClientMixes(); }; #endif /* defined(__hifi__AudioMixer__) */ From 6d162ff7a700b6fc3b2095047f781fc9e48de10c Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 3 Dec 2013 10:07:40 -0800 Subject: [PATCH 13/31] process any new events at beginning of Assignment while loop --- assignment-client/src/audio/AudioMixer.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 5e4e2596b4..abaa4f7f80 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -304,13 +304,12 @@ void AudioMixer::run() { while (!_isFinished) { - // get the NodeList to ping any inactive nodes, for hole punching - nodeList->possiblyPingInactiveNodes(); - - int numBytesPacketHeader = numBytesForPacketHeader((unsigned char*) &PACKET_TYPE_MIXED_AUDIO); - unsigned char clientPacket[BUFFER_LENGTH_BYTES_STEREO + numBytesPacketHeader]; - populateTypeAndVersion(clientPacket, PACKET_TYPE_MIXED_AUDIO); + QCoreApplication::processEvents(); + if (_isFinished) { + break; + } + for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { if (node->getLinkedData()) { ((AudioMixerClientData*) node->getLinkedData())->checkBuffersBeforeFrameSend(JITTER_BUFFER_SAMPLES); @@ -336,7 +335,8 @@ void AudioMixer::run() { } } - QCoreApplication::processEvents(); + // get the NodeList to ping any inactive nodes, for hole punching + nodeList->possiblyPingInactiveNodes(); int usecToSleep = usecTimestamp(&startTime) + (++nextFrame * BUFFER_SEND_INTERVAL_USECS) - usecTimestampNow(); From 6ce8c12cb711d724721c94d98d58fe3a0d3a441a Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 3 Dec 2013 10:09:38 -0800 Subject: [PATCH 14/31] remove timing debug for DS check in --- assignment-client/src/audio/AudioMixer.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index abaa4f7f80..106a19f353 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -251,12 +251,7 @@ void AudioMixer::processDatagram(const QByteArray& dataByteArray, const HifiSock } } -timeval lastCall = {}; - void AudioMixer::checkInWithDomainServerOrExit() { - qDebug() << (usecTimestampNow() - usecTimestamp(&lastCall)) << "\n"; - gettimeofday(&lastCall, NULL); - if (NodeList::getInstance()->getNumNoReplyDomainCheckIns() == MAX_SILENT_DOMAIN_SERVER_CHECK_INS) { _isFinished = true; emit finished(); From c3b6a7b24c9bd0a4506b6b93f9a6c9780552d338 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 3 Dec 2013 10:22:13 -0800 Subject: [PATCH 15/31] setup subclass for threaded assignments --- assignment-client/src/AssignmentClient.cpp | 4 +-- assignment-client/src/AssignmentClient.h | 4 ++- assignment-client/src/ThreadedAssignment.cpp | 32 ++++++++++++++++++ assignment-client/src/ThreadedAssignment.h | 34 ++++++++++++++++++++ assignment-client/src/audio/AudioMixer.cpp | 26 +++------------ assignment-client/src/audio/AudioMixer.h | 16 +++------ assignment-client/src/main.cpp | 1 - libraries/shared/src/Assignment.cpp | 4 --- libraries/shared/src/Assignment.h | 3 -- libraries/shared/src/PacketHeaders.cpp | 2 +- 10 files changed, 81 insertions(+), 45 deletions(-) create mode 100644 assignment-client/src/ThreadedAssignment.cpp create mode 100644 assignment-client/src/ThreadedAssignment.h diff --git a/assignment-client/src/AssignmentClient.cpp b/assignment-client/src/AssignmentClient.cpp index 650b88c47b..f20e0da2a5 100644 --- a/assignment-client/src/AssignmentClient.cpp +++ b/assignment-client/src/AssignmentClient.cpp @@ -80,7 +80,7 @@ void AssignmentClient::readPendingDatagrams() { qDebug() << "Dropping received assignment since we are currently running one.\n"; } else { // construct the deployed assignment from the packet data - _currentAssignment = AssignmentFactory::unpackAssignment(packetData, receivedBytes); + _currentAssignment = (ThreadedAssignment*) AssignmentFactory::unpackAssignment(packetData, receivedBytes); qDebug() << "Received an assignment -" << *_currentAssignment << "\n"; @@ -95,7 +95,7 @@ void AssignmentClient::readPendingDatagrams() { // start the deployed assignment QThread* workerThread = new QThread(this); - connect(workerThread, SIGNAL(started()), _currentAssignment, SLOT(setup())); + connect(workerThread, SIGNAL(started()), _currentAssignment, SLOT(run())); connect(_currentAssignment, SIGNAL(finished()), this, SLOT(assignmentCompleted())); connect(_currentAssignment, SIGNAL(finished()), workerThread, SLOT(quit())); diff --git a/assignment-client/src/AssignmentClient.h b/assignment-client/src/AssignmentClient.h index b826f40a63..48311b0275 100644 --- a/assignment-client/src/AssignmentClient.h +++ b/assignment-client/src/AssignmentClient.h @@ -11,6 +11,8 @@ #include +#include "ThreadedAssignment.h" + class AssignmentClient : public QCoreApplication { Q_OBJECT public: @@ -24,7 +26,7 @@ private slots: void assignmentCompleted(); private: Assignment _requestAssignment; - Assignment* _currentAssignment; + ThreadedAssignment* _currentAssignment; }; #endif /* defined(__hifi__AssignmentClient__) */ diff --git a/assignment-client/src/ThreadedAssignment.cpp b/assignment-client/src/ThreadedAssignment.cpp new file mode 100644 index 0000000000..095999adca --- /dev/null +++ b/assignment-client/src/ThreadedAssignment.cpp @@ -0,0 +1,32 @@ +// +// ThreadedAssignment.cpp +// hifi +// +// Created by Stephen Birarda on 12/3/2013. +// Copyright (c) 2013 HighFidelity, Inc. All rights reserved. +// + +#include "ThreadedAssignment.h" + +ThreadedAssignment::ThreadedAssignment(const unsigned char* dataBuffer, int numBytes) : + Assignment(dataBuffer, numBytes), + _isFinished(false) +{ + +} + +void ThreadedAssignment::setFinished(bool isFinished) { + _isFinished = isFinished; + + if (_isFinished) { + emit finished(); + } +} + +void ThreadedAssignment::checkInWithDomainServerOrExit() { + if (NodeList::getInstance()->getNumNoReplyDomainCheckIns() == MAX_SILENT_DOMAIN_SERVER_CHECK_INS) { + setFinished(true); + } else { + NodeList::getInstance()->sendDomainServerCheckIn(); + } +} diff --git a/assignment-client/src/ThreadedAssignment.h b/assignment-client/src/ThreadedAssignment.h new file mode 100644 index 0000000000..15391f9122 --- /dev/null +++ b/assignment-client/src/ThreadedAssignment.h @@ -0,0 +1,34 @@ +// +// ThreadedAssignment.h +// hifi +// +// Created by Stephen Birarda on 12/3/2013. +// Copyright (c) 2013 HighFidelity, Inc. All rights reserved. +// + +#ifndef __hifi__ThreadedAssignment__ +#define __hifi__ThreadedAssignment__ + +#include + +class ThreadedAssignment : public Assignment { + Q_OBJECT +public: + ThreadedAssignment(const unsigned char* dataBuffer, int numBytes); + + void setFinished(bool isFinished); +public slots: + /// threaded run of assignment + virtual void run() = 0; + + virtual void processDatagram(const QByteArray& dataByteArray, const HifiSockAddr& senderSockAddr) = 0; +protected: + bool _isFinished; +private slots: + void checkInWithDomainServerOrExit(); +signals: + void finished(); +}; + + +#endif /* defined(__hifi__ThreadedAssignment__) */ diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 106a19f353..92b36d054e 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -68,8 +68,7 @@ void attachNewBufferToNode(Node *newNode) { } AudioMixer::AudioMixer(const unsigned char* dataBuffer, int numBytes) : - Assignment(dataBuffer, numBytes), - _isFinished(false) + ThreadedAssignment(dataBuffer, numBytes) { } @@ -251,21 +250,13 @@ void AudioMixer::processDatagram(const QByteArray& dataByteArray, const HifiSock } } -void AudioMixer::checkInWithDomainServerOrExit() { - if (NodeList::getInstance()->getNumNoReplyDomainCheckIns() == MAX_SILENT_DOMAIN_SERVER_CHECK_INS) { - _isFinished = true; - emit finished(); - } else { - NodeList::getInstance()->sendDomainServerCheckIn(); - } -} - - -void AudioMixer::setup() { +void AudioMixer::run() { + + NodeList* nodeList = NodeList::getInstance(); + // change the logging target name while this is running Logging::setTargetName(AUDIO_MIXER_LOGGING_TARGET_NAME); - NodeList *nodeList = NodeList::getInstance(); nodeList->setOwnerType(NODE_TYPE_AUDIO_MIXER); const char AUDIO_MIXER_NODE_TYPES_OF_INTEREST[2] = { NODE_TYPE_AGENT, NODE_TYPE_AUDIO_INJECTOR }; @@ -281,13 +272,6 @@ void AudioMixer::setup() { connect(silentNodeTimer, SIGNAL(timeout()), nodeList, SLOT(removeSilentNodes())); silentNodeTimer->start(NODE_SILENCE_THRESHOLD_USECS / 1000); - run(); -} - -void AudioMixer::run() { - - NodeList* nodeList = NodeList::getInstance(); - int nextFrame = 0; timeval startTime; diff --git a/assignment-client/src/audio/AudioMixer.h b/assignment-client/src/audio/AudioMixer.h index b38d553564..a219919a1c 100644 --- a/assignment-client/src/audio/AudioMixer.h +++ b/assignment-client/src/audio/AudioMixer.h @@ -9,28 +9,23 @@ #ifndef __hifi__AudioMixer__ #define __hifi__AudioMixer__ - -#include #include +#include "../ThreadedAssignment.h" + class PositionalAudioRingBuffer; class AvatarAudioRingBuffer; /// Handles assignments of type AudioMixer - mixing streams of audio and re-distributing to various clients. -class AudioMixer : public Assignment { +class AudioMixer : public ThreadedAssignment { Q_OBJECT public: AudioMixer(const unsigned char* dataBuffer, int numBytes); public slots: - /// performs setup for the audio mixer - void setup(); - - /// performs run of audio mixer + /// threaded run of assignment void run(); void processDatagram(const QByteArray& dataByteArray, const HifiSockAddr& senderSockAddr); -signals: - void finished(); private: /// adds one buffer to the mix for a listening node void addBufferToMixForListeningNodeWithBuffer(PositionalAudioRingBuffer* bufferToAdd, @@ -41,9 +36,6 @@ private: int16_t _clientSamples[BUFFER_LENGTH_SAMPLES_PER_CHANNEL * 2]; - bool _isFinished; -private slots: - void checkInWithDomainServerOrExit(); }; #endif /* defined(__hifi__AudioMixer__) */ diff --git a/assignment-client/src/main.cpp b/assignment-client/src/main.cpp index ae4f569f83..28516b37b8 100644 --- a/assignment-client/src/main.cpp +++ b/assignment-client/src/main.cpp @@ -21,7 +21,6 @@ #include "Agent.h" #include "Assignment.h" #include "AssignmentClient.h" -#include "AssignmentFactory.h" #include "audio/AudioMixer.h" #include "avatars/AvatarMixer.h" diff --git a/libraries/shared/src/Assignment.cpp b/libraries/shared/src/Assignment.cpp index 07e96e4963..59b0bb60d1 100644 --- a/libraries/shared/src/Assignment.cpp +++ b/libraries/shared/src/Assignment.cpp @@ -211,10 +211,6 @@ int Assignment::packToBuffer(unsigned char* buffer) { return numPackedBytes; } -void Assignment::run() { - // run method ovveridden by subclasses -} - QDebug operator<<(QDebug debug, const Assignment &assignment) { debug.nospace() << "UUID: " << assignment.getUUID().toString().toStdString().c_str() << ", Type: " << assignment.getType(); diff --git a/libraries/shared/src/Assignment.h b/libraries/shared/src/Assignment.h index 68e23e761d..d862fda859 100644 --- a/libraries/shared/src/Assignment.h +++ b/libraries/shared/src/Assignment.h @@ -90,9 +90,6 @@ public: // implement parseData to return 0 so we can be a subclass of NodeData int parseData(unsigned char* sourceBuffer, int numBytes) { return 0; } - /// threaded run of assignment - virtual void run(); - friend QDebug operator<<(QDebug debug, const Assignment& assignment); friend QDataStream& operator<<(QDataStream &out, const Assignment& assignment); friend QDataStream& operator>>(QDataStream &in, Assignment& assignment); diff --git a/libraries/shared/src/PacketHeaders.cpp b/libraries/shared/src/PacketHeaders.cpp index b03daeec05..d320a066ee 100644 --- a/libraries/shared/src/PacketHeaders.cpp +++ b/libraries/shared/src/PacketHeaders.cpp @@ -34,7 +34,7 @@ PACKET_VERSION versionForPacketType(PACKET_TYPE type) { case PACKET_TYPE_DOMAIN: case PACKET_TYPE_DOMAIN_LIST_REQUEST: case PACKET_TYPE_DOMAIN_REPORT_FOR_DUTY: - return 1; + return 2; case PACKET_TYPE_VOXEL_QUERY: return 1; From 606eaa579adc64262c394b0f9fd7dae89d20fc34 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 3 Dec 2013 10:57:31 -0800 Subject: [PATCH 16/31] switch node pinging to QTimer in QCoreApplication instance --- assignment-client/src/audio/AudioMixer.cpp | 7 ++++--- libraries/shared/src/NodeList.cpp | 20 ++++++------------- libraries/shared/src/NodeList.h | 5 +++-- .../voxel-server-library/src/VoxelServer.cpp | 2 +- 4 files changed, 14 insertions(+), 20 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 92b36d054e..edc02ec161 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -272,6 +272,10 @@ void AudioMixer::run() { connect(silentNodeTimer, SIGNAL(timeout()), nodeList, SLOT(removeSilentNodes())); silentNodeTimer->start(NODE_SILENCE_THRESHOLD_USECS / 1000); + QTimer* pingNodesTimer = new QTimer(this); + connect(pingNodesTimer, SIGNAL(timeout()), nodeList, SLOT(pingInactiveNodes())); + pingNodesTimer->start(PING_INACTIVE_NODE_INTERVAL_USECS / 1000); + int nextFrame = 0; timeval startTime; @@ -314,9 +318,6 @@ void AudioMixer::run() { } } - // get the NodeList to ping any inactive nodes, for hole punching - nodeList->possiblyPingInactiveNodes(); - int usecToSleep = usecTimestamp(&startTime) + (++nextFrame * BUFFER_SEND_INTERVAL_USECS) - usecTimestampNow(); if (usecToSleep > 0) { diff --git a/libraries/shared/src/NodeList.cpp b/libraries/shared/src/NodeList.cpp index 16b55bd1db..14e1bbfde8 100644 --- a/libraries/shared/src/NodeList.cpp +++ b/libraries/shared/src/NodeList.cpp @@ -724,20 +724,12 @@ unsigned NodeList::broadcastToNodes(unsigned char* broadcastData, size_t dataByt return n; } -const uint64_t PING_INACTIVE_NODE_INTERVAL_USECS = 1 * 1000 * 1000; - -void NodeList::possiblyPingInactiveNodes() { - static timeval lastPing = {}; - - // make sure PING_INACTIVE_NODE_INTERVAL_USECS has elapsed since last ping - if (usecTimestampNow() - usecTimestamp(&lastPing) >= PING_INACTIVE_NODE_INTERVAL_USECS) { - gettimeofday(&lastPing, NULL); - - for(NodeList::iterator node = begin(); node != end(); node++) { - if (!node->getActiveSocket()) { - // we don't have an active link to this node, ping it to set that up - pingPublicAndLocalSocketsForInactiveNode(&(*node)); - } +void NodeList::pingInactiveNodes() { + qDebug() << "Pinging inactive nodes\n"; + for(NodeList::iterator node = begin(); node != end(); node++) { + if (!node->getActiveSocket()) { + // we don't have an active link to this node, ping it to set that up + pingPublicAndLocalSocketsForInactiveNode(&(*node)); } } } diff --git a/libraries/shared/src/NodeList.h b/libraries/shared/src/NodeList.h index b5d9b1e31e..250474ee75 100644 --- a/libraries/shared/src/NodeList.h +++ b/libraries/shared/src/NodeList.h @@ -31,7 +31,8 @@ const int NODES_PER_BUCKET = 100; const int MAX_PACKET_SIZE = 1500; const uint64_t NODE_SILENCE_THRESHOLD_USECS = 2 * 1000 * 1000; -const int DOMAIN_SERVER_CHECK_IN_USECS = 1 * 1000000; +const uint64_t DOMAIN_SERVER_CHECK_IN_USECS = 1 * 1000000; +const uint64_t PING_INACTIVE_NODE_INTERVAL_USECS = 1 * 1000 * 1000; extern const char SOLO_NODE_TYPES[2]; @@ -141,10 +142,10 @@ public: void addDomainListener(DomainChangeListener* listener); void removeDomainListener(DomainChangeListener* listener); - void possiblyPingInactiveNodes(); const HifiSockAddr* getNodeActiveSocketOrPing(Node* node); public slots: void sendDomainServerCheckIn(); + void pingInactiveNodes(); void removeSilentNodes(); private: static NodeList* _sharedInstance; diff --git a/libraries/voxel-server-library/src/VoxelServer.cpp b/libraries/voxel-server-library/src/VoxelServer.cpp index 5fd87f52ec..58392e3c31 100644 --- a/libraries/voxel-server-library/src/VoxelServer.cpp +++ b/libraries/voxel-server-library/src/VoxelServer.cpp @@ -666,7 +666,7 @@ void VoxelServer::run() { } // ping our inactive nodes to punch holes with them - nodeList->possiblyPingInactiveNodes(); + nodeList->pingInactiveNodes(); if (nodeList->getNodeSocket().hasPendingDatagrams() && (packetLength = nodeList->getNodeSocket().readDatagram((char*) packetData, MAX_PACKET_SIZE, From ed854dcb7bf34ef441a01ee33061dfc373bbdac1 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 3 Dec 2013 10:58:04 -0800 Subject: [PATCH 17/31] re-work AvatarMixer to new QCA infrastructure, closes #1300 --- assignment-client/src/avatars/AvatarMixer.cpp | 201 ++++++++++-------- assignment-client/src/avatars/AvatarMixer.h | 7 +- 2 files changed, 118 insertions(+), 90 deletions(-) diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index 9a629a8ef6..6235bbd81d 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -10,6 +10,9 @@ // The avatar mixer receives head, hand and positional data from all connected // nodes, and broadcasts that data back to them, every BROADCAST_INTERVAL ms. +#include +#include + #include #include #include @@ -22,6 +25,14 @@ const char AVATAR_MIXER_LOGGING_NAME[] = "avatar-mixer"; +const unsigned int AVATAR_DATA_SEND_INTERVAL_USECS = (1 / 60.0) * 1000 * 1000; + +AvatarMixer::AvatarMixer(const unsigned char* dataBuffer, int numBytes) : + ThreadedAssignment(dataBuffer, numBytes) +{ + +} + unsigned char* addNodeToBroadcastPacket(unsigned char *currentPosition, Node *nodeToAdd) { QByteArray rfcUUID = nodeToAdd->getUUID().toRfc4122(); memcpy(currentPosition, rfcUUID.constData(), rfcUUID.size()); @@ -46,7 +57,7 @@ void attachAvatarDataToNode(Node* newNode) { // 3) if we need to rate limit the amount of data we send, we can use a distance weighted "semi-random" function to // determine which avatars are included in the packet stream // 4) we should optimize the avatar data format to be more compact (100 bytes is pretty wasteful). -void broadcastAvatarData(NodeList* nodeList, const QUuid& receiverUUID, const HifiSockAddr& receiverSockAddr) { +void broadcastAvatarData() { static unsigned char broadcastPacketBuffer[MAX_PACKET_SIZE]; static unsigned char avatarDataBuffer[MAX_PACKET_SIZE]; unsigned char* broadcastPacket = (unsigned char*)&broadcastPacketBuffer[0]; @@ -55,40 +66,91 @@ void broadcastAvatarData(NodeList* nodeList, const QUuid& receiverUUID, const Hi int packetLength = currentBufferPosition - broadcastPacket; int packetsSent = 0; - // send back a packet with other active node data to this node + NodeList* nodeList = NodeList::getInstance(); + for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { - if (node->getLinkedData() && node->getUUID() != receiverUUID) { - unsigned char* avatarDataEndpoint = addNodeToBroadcastPacket((unsigned char*)&avatarDataBuffer[0], &*node); - int avatarDataLength = avatarDataEndpoint - (unsigned char*)&avatarDataBuffer; - - if (avatarDataLength + packetLength <= MAX_PACKET_SIZE) { - memcpy(currentBufferPosition, &avatarDataBuffer[0], avatarDataLength); - packetLength += avatarDataLength; - currentBufferPosition += avatarDataLength; - } else { - packetsSent++; - //printf("packetsSent=%d packetLength=%d\n", packetsSent, packetLength); - nodeList->getNodeSocket().writeDatagram((char*) broadcastPacket, currentBufferPosition - broadcastPacket, - receiverSockAddr.getAddress(), receiverSockAddr.getPort()); - - // reset the packet - currentBufferPosition = broadcastPacket + numHeaderBytes; - packetLength = currentBufferPosition - broadcastPacket; - - // copy the avatar that didn't fit into the next packet - memcpy(currentBufferPosition, &avatarDataBuffer[0], avatarDataLength); - packetLength += avatarDataLength; - currentBufferPosition += avatarDataLength; + if (node->getLinkedData() && node->getType() == NODE_TYPE_AGENT && node->getActiveSocket()) { + // this is an AGENT we have received head data from + // send back a packet with other active node data to this node + for (NodeList::iterator otherNode = nodeList->begin(); otherNode != nodeList->end(); otherNode++) { + if (otherNode->getLinkedData() && otherNode->getUUID() != node->getUUID()) { + unsigned char* avatarDataEndpoint = addNodeToBroadcastPacket((unsigned char*)&avatarDataBuffer[0], &*node); + int avatarDataLength = avatarDataEndpoint - (unsigned char*)&avatarDataBuffer; + + if (avatarDataLength + packetLength <= MAX_PACKET_SIZE) { + memcpy(currentBufferPosition, &avatarDataBuffer[0], avatarDataLength); + packetLength += avatarDataLength; + currentBufferPosition += avatarDataLength; + } else { + packetsSent++; + //printf("packetsSent=%d packetLength=%d\n", packetsSent, packetLength); + nodeList->getNodeSocket().writeDatagram((char*) broadcastPacket, currentBufferPosition - broadcastPacket, + node->getActiveSocket()->getAddress(), + node->getActiveSocket()->getPort()); + + // reset the packet + currentBufferPosition = broadcastPacket + numHeaderBytes; + packetLength = currentBufferPosition - broadcastPacket; + + // copy the avatar that didn't fit into the next packet + memcpy(currentBufferPosition, &avatarDataBuffer[0], avatarDataLength); + packetLength += avatarDataLength; + currentBufferPosition += avatarDataLength; + } + } } + + packetsSent++; + //printf("packetsSent=%d packetLength=%d\n", packetsSent, packetLength); + NodeList::getInstance()->getNodeSocket().writeDatagram((char*) broadcastPacket, currentBufferPosition - broadcastPacket, + node->getActiveSocket()->getAddress(), + node->getActiveSocket()->getPort()); } } - packetsSent++; - //printf("packetsSent=%d packetLength=%d\n", packetsSent, packetLength); - nodeList->getNodeSocket().writeDatagram((char*) broadcastPacket, currentBufferPosition - broadcastPacket, - receiverSockAddr.getAddress(), receiverSockAddr.getPort()); + + } -AvatarMixer::AvatarMixer(const unsigned char* dataBuffer, int numBytes) : Assignment(dataBuffer, numBytes) { +void AvatarMixer::processDatagram(const QByteArray& dataByteArray, const HifiSockAddr& senderSockAddr) { + + NodeList* nodeList = NodeList::getInstance(); + + switch (dataByteArray.data()[0]) { + case PACKET_TYPE_HEAD_DATA: { + QUuid nodeUUID = QUuid::fromRfc4122(dataByteArray.mid(numBytesForPacketHeader((unsigned char*) dataByteArray.data()), + NUM_BYTES_RFC4122_UUID)); + + // add or update the node in our list + Node* avatarNode = nodeList->nodeWithUUID(nodeUUID); + + if (avatarNode) { + // parse positional data from an node + nodeList->updateNodeWithData(avatarNode, senderSockAddr, + (unsigned char*) dataByteArray.data(), dataByteArray.size()); + } else { + break; + } + } + case PACKET_TYPE_KILL_NODE: + case PACKET_TYPE_AVATAR_URLS: + case PACKET_TYPE_AVATAR_FACE_VIDEO: { + QUuid nodeUUID = QUuid::fromRfc4122(dataByteArray.mid(numBytesForPacketHeader((unsigned char*) dataByteArray.data()), + NUM_BYTES_RFC4122_UUID)); + // let everyone else know about the update + for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { + if (node->getActiveSocket() && node->getUUID() != nodeUUID) { + nodeList->getNodeSocket().writeDatagram(dataByteArray, + node->getActiveSocket()->getAddress(), + node->getActiveSocket()->getPort()); + } + } + // let node kills fall through to default behavior + } + default: + // hand this off to the NodeList + nodeList->processNodeData(senderSockAddr, (unsigned char*) dataByteArray.data(), dataByteArray.size()); + break; + } } @@ -103,76 +165,39 @@ void AvatarMixer::run() { nodeList->linkedDataCreateCallback = attachAvatarDataToNode; - nodeList->startSilentNodeRemovalThread(); + QTimer* domainServerTimer = new QTimer(this); + connect(domainServerTimer, SIGNAL(timeout()), this, SLOT(checkInWithDomainServerOrExit())); + domainServerTimer->start(DOMAIN_SERVER_CHECK_IN_USECS / 1000); - HifiSockAddr nodeSockAddr; - ssize_t receivedBytes = 0; + QTimer* pingNodesTimer = new QTimer(this); + connect(pingNodesTimer, SIGNAL(timeout()), nodeList, SLOT(pingInactiveNodes())); + pingNodesTimer->start(PING_INACTIVE_NODE_INTERVAL_USECS / 1000); - unsigned char packetData[MAX_PACKET_SIZE]; + QTimer* silentNodeTimer = new QTimer(this); + connect(silentNodeTimer, SIGNAL(timeout()), nodeList, SLOT(removeSilentNodes())); + silentNodeTimer->start(NODE_SILENCE_THRESHOLD_USECS / 1000); - QUuid nodeUUID; - Node* avatarNode = NULL; + int nextFrame = 0; + timeval startTime; - timeval lastDomainServerCheckIn = {}; + gettimeofday(&startTime, NULL); - while (true) { + while (!_isFinished) { - if (NodeList::getInstance()->getNumNoReplyDomainCheckIns() == MAX_SILENT_DOMAIN_SERVER_CHECK_INS) { + QCoreApplication::processEvents(); + + if (_isFinished) { break; } - // 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(); - } + broadcastAvatarData(); - nodeList->possiblyPingInactiveNodes(); + int usecToSleep = usecTimestamp(&startTime) + (++nextFrame * AVATAR_DATA_SEND_INTERVAL_USECS) - usecTimestampNow(); - if (nodeList->getNodeSocket().hasPendingDatagrams() && - (receivedBytes = nodeList->getNodeSocket().readDatagram((char*) packetData, MAX_PACKET_SIZE, - nodeSockAddr.getAddressPointer(), - nodeSockAddr.getPortPointer())) && - packetVersionMatch(packetData)) { - switch (packetData[0]) { - case PACKET_TYPE_HEAD_DATA: - nodeUUID = QUuid::fromRfc4122(QByteArray((char*) packetData + numBytesForPacketHeader(packetData), - NUM_BYTES_RFC4122_UUID)); - - // add or update the node in our list - avatarNode = nodeList->nodeWithUUID(nodeUUID); - - if (avatarNode) { - // parse positional data from an node - nodeList->updateNodeWithData(avatarNode, nodeSockAddr, packetData, receivedBytes); - } else { - break; - } - case PACKET_TYPE_INJECT_AUDIO: - broadcastAvatarData(nodeList, nodeUUID, nodeSockAddr); - break; - case PACKET_TYPE_KILL_NODE: - case PACKET_TYPE_AVATAR_URLS: - case PACKET_TYPE_AVATAR_FACE_VIDEO: - nodeUUID = QUuid::fromRfc4122(QByteArray((char*) packetData + numBytesForPacketHeader(packetData), - NUM_BYTES_RFC4122_UUID)); - // let everyone else know about the update - for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { - if (node->getActiveSocket() && node->getUUID() != nodeUUID) { - nodeList->getNodeSocket().writeDatagram((char*) packetData, receivedBytes, - node->getActiveSocket()->getAddress(), - node->getActiveSocket()->getPort()); - } - } - // let node kills fall through to default behavior - - default: - // hand this off to the NodeList - nodeList->processNodeData(nodeSockAddr, packetData, receivedBytes); - break; - } + if (usecToSleep > 0) { + usleep(usecToSleep); + } else { + qDebug() << "Took too much time, not sleeping!\n"; } } - - nodeList->stopSilentNodeRemovalThread(); } diff --git a/assignment-client/src/avatars/AvatarMixer.h b/assignment-client/src/avatars/AvatarMixer.h index 41a584a296..a13cdaa073 100644 --- a/assignment-client/src/avatars/AvatarMixer.h +++ b/assignment-client/src/avatars/AvatarMixer.h @@ -9,15 +9,18 @@ #ifndef __hifi__AvatarMixer__ #define __hifi__AvatarMixer__ -#include +#include "../ThreadedAssignment.h" /// Handles assignments of type AvatarMixer - distribution of avatar data to various clients -class AvatarMixer : public Assignment { +class AvatarMixer : public ThreadedAssignment { public: AvatarMixer(const unsigned char* dataBuffer, int numBytes); +public slots: /// runs the avatar mixer void run(); + + void processDatagram(const QByteArray& dataByteArray, const HifiSockAddr& senderSockAddr); }; #endif /* defined(__hifi__AvatarMixer__) */ From 6f7e16dc22be4034b5b9f51391c332ecd9af8f78 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 3 Dec 2013 11:11:08 -0800 Subject: [PATCH 18/31] hook VS to new QCA infrastructure --- assignment-client/src/audio/AudioMixer.h | 2 +- assignment-client/src/avatars/AvatarMixer.h | 2 +- libraries/shared/src/NodeList.cpp | 1 - .../shared}/src/ThreadedAssignment.cpp | 0 .../shared}/src/ThreadedAssignment.h | 2 +- .../voxel-server-library/src/VoxelServer.cpp | 180 +++++++++--------- .../voxel-server-library/src/VoxelServer.h | 11 +- 7 files changed, 99 insertions(+), 99 deletions(-) rename {assignment-client => libraries/shared}/src/ThreadedAssignment.cpp (100%) rename {assignment-client => libraries/shared}/src/ThreadedAssignment.h (97%) diff --git a/assignment-client/src/audio/AudioMixer.h b/assignment-client/src/audio/AudioMixer.h index a219919a1c..2c07e8747a 100644 --- a/assignment-client/src/audio/AudioMixer.h +++ b/assignment-client/src/audio/AudioMixer.h @@ -11,7 +11,7 @@ #include -#include "../ThreadedAssignment.h" +#include class PositionalAudioRingBuffer; class AvatarAudioRingBuffer; diff --git a/assignment-client/src/avatars/AvatarMixer.h b/assignment-client/src/avatars/AvatarMixer.h index a13cdaa073..c2158fad1c 100644 --- a/assignment-client/src/avatars/AvatarMixer.h +++ b/assignment-client/src/avatars/AvatarMixer.h @@ -9,7 +9,7 @@ #ifndef __hifi__AvatarMixer__ #define __hifi__AvatarMixer__ -#include "../ThreadedAssignment.h" +#include /// Handles assignments of type AvatarMixer - distribution of avatar data to various clients class AvatarMixer : public ThreadedAssignment { diff --git a/libraries/shared/src/NodeList.cpp b/libraries/shared/src/NodeList.cpp index 14e1bbfde8..3df90d4377 100644 --- a/libraries/shared/src/NodeList.cpp +++ b/libraries/shared/src/NodeList.cpp @@ -725,7 +725,6 @@ unsigned NodeList::broadcastToNodes(unsigned char* broadcastData, size_t dataByt } void NodeList::pingInactiveNodes() { - qDebug() << "Pinging inactive nodes\n"; for(NodeList::iterator node = begin(); node != end(); node++) { if (!node->getActiveSocket()) { // we don't have an active link to this node, ping it to set that up diff --git a/assignment-client/src/ThreadedAssignment.cpp b/libraries/shared/src/ThreadedAssignment.cpp similarity index 100% rename from assignment-client/src/ThreadedAssignment.cpp rename to libraries/shared/src/ThreadedAssignment.cpp diff --git a/assignment-client/src/ThreadedAssignment.h b/libraries/shared/src/ThreadedAssignment.h similarity index 97% rename from assignment-client/src/ThreadedAssignment.h rename to libraries/shared/src/ThreadedAssignment.h index 15391f9122..2d6e49b724 100644 --- a/assignment-client/src/ThreadedAssignment.h +++ b/libraries/shared/src/ThreadedAssignment.h @@ -9,7 +9,7 @@ #ifndef __hifi__ThreadedAssignment__ #define __hifi__ThreadedAssignment__ -#include +#include "Assignment.h" class ThreadedAssignment : public Assignment { Q_OBJECT diff --git a/libraries/voxel-server-library/src/VoxelServer.cpp b/libraries/voxel-server-library/src/VoxelServer.cpp index 58392e3c31..2653d63ccf 100644 --- a/libraries/voxel-server-library/src/VoxelServer.cpp +++ b/libraries/voxel-server-library/src/VoxelServer.cpp @@ -14,6 +14,7 @@ #include #include +#include #include #include @@ -53,8 +54,10 @@ void attachVoxelNodeDataToNode(Node* newNode) { VoxelServer* VoxelServer::_theInstance = NULL; -VoxelServer::VoxelServer(const unsigned char* dataBuffer, int numBytes) : Assignment(dataBuffer, numBytes), - _serverTree(true) { +VoxelServer::VoxelServer(const unsigned char* dataBuffer, int numBytes) : + ThreadedAssignment(dataBuffer, numBytes), + _serverTree(true) +{ _argc = 0; _argv = NULL; @@ -466,6 +469,77 @@ void VoxelServer::parsePayload() { } } +void VoxelServer::processDatagram(const QByteArray& dataByteArray, const HifiSockAddr& senderSockAddr) { + NodeList* nodeList = NodeList::getInstance(); + + int numBytesPacketHeader = numBytesForPacketHeader((unsigned char*)dataByteArray.data()); + + if (dataByteArray.data()[0] == PACKET_TYPE_VOXEL_QUERY) { + // If we got a PACKET_TYPE_VOXEL_QUERY, then we're talking to an NODE_TYPE_AVATAR, and we + // need to make sure we have it in our nodeList. + QUuid nodeUUID = QUuid::fromRfc4122(dataByteArray.mid(numBytesForPacketHeader((unsigned char*) dataByteArray.data()), + NUM_BYTES_RFC4122_UUID)); + + Node* node = nodeList->nodeWithUUID(nodeUUID); + + if (node) { + nodeList->updateNodeWithData(node, senderSockAddr, (unsigned char*) dataByteArray.data(), dataByteArray.size()); + if (!node->getActiveSocket()) { + // we don't have an active socket for this node, but they're talking to us + // this means they've heard from us and can reply, let's assume public is active + node->activatePublicSocket(); + } + VoxelNodeData* nodeData = (VoxelNodeData*) node->getLinkedData(); + if (nodeData && !nodeData->isVoxelSendThreadInitalized()) { + nodeData->initializeVoxelSendThread(this); + } + } + } else if (dataByteArray.data()[0] == PACKET_TYPE_VOXEL_JURISDICTION_REQUEST) { + if (_jurisdictionSender) { + _jurisdictionSender->queueReceivedPacket(senderSockAddr, + (unsigned char*) dataByteArray.data(), dataByteArray.size()); + } + } else if (_voxelServerPacketProcessor && + (dataByteArray.data()[0] == PACKET_TYPE_SET_VOXEL + || dataByteArray.data()[0] == PACKET_TYPE_SET_VOXEL_DESTRUCTIVE + || dataByteArray.data()[0] == PACKET_TYPE_ERASE_VOXEL + || dataByteArray.data()[0] == PACKET_TYPE_Z_COMMAND)) { + + const char* messageName; + switch (dataByteArray.data()[0]) { + case PACKET_TYPE_SET_VOXEL: + messageName = "PACKET_TYPE_SET_VOXEL"; + break; + case PACKET_TYPE_SET_VOXEL_DESTRUCTIVE: + messageName = "PACKET_TYPE_SET_VOXEL_DESTRUCTIVE"; + break; + case PACKET_TYPE_ERASE_VOXEL: + messageName = "PACKET_TYPE_ERASE_VOXEL"; + break; + } + + if (dataByteArray.data()[0] != PACKET_TYPE_Z_COMMAND) { + unsigned short int sequence = (*((unsigned short int*)(dataByteArray.data() + numBytesPacketHeader))); + uint64_t sentAt = (*((uint64_t*)(dataByteArray.data() + numBytesPacketHeader + sizeof(sequence)))); + uint64_t arrivedAt = usecTimestampNow(); + uint64_t transitTime = arrivedAt - sentAt; + if (wantShowAnimationDebug() || wantsDebugVoxelReceiving()) { + printf("RECEIVE THREAD: got %s - command from client receivedBytes=%d sequence=%d transitTime=%llu usecs\n", + messageName, + dataByteArray.size(), sequence, transitTime); + } + } + + _voxelServerPacketProcessor->queueReceivedPacket(senderSockAddr, + (unsigned char*) dataByteArray.data(), dataByteArray.size()); + } else { + // let processNodeData handle it. + NodeList::getInstance()->processNodeData(senderSockAddr, + (unsigned char*) dataByteArray.data(), + dataByteArray.size()); + } +} + //int main(int argc, const char * argv[]) { void VoxelServer::run() { @@ -622,8 +696,6 @@ void VoxelServer::run() { unsigned char* packetData = new unsigned char[MAX_PACKET_SIZE]; ssize_t packetLength; - - timeval lastDomainServerCheckIn = {}; // set up our jurisdiction broadcaster... _jurisdictionSender = new JurisdictionSender(_jurisdiction); @@ -650,95 +722,21 @@ void VoxelServer::run() { } qDebug() << "Now running... started at: " << localBuffer << utcBuffer << "\n"; + QTimer* domainServerTimer = new QTimer(this); + connect(domainServerTimer, SIGNAL(timeout()), this, SLOT(checkInWithDomainServerOrExit())); + domainServerTimer->start(DOMAIN_SERVER_CHECK_IN_USECS / 1000); + + QTimer* silentNodeTimer = new QTimer(this); + connect(silentNodeTimer, SIGNAL(timeout()), nodeList, SLOT(removeSilentNodes())); + silentNodeTimer->start(NODE_SILENCE_THRESHOLD_USECS / 1000); + + QTimer* pingNodesTimer = new QTimer(this); + connect(pingNodesTimer, SIGNAL(timeout()), nodeList, SLOT(pingInactiveNodes())); + pingNodesTimer->start(PING_INACTIVE_NODE_INTERVAL_USECS / 1000); // loop to send to nodes requesting data - while (true) { - // check for >= in case one gets past the goalie - if (NodeList::getInstance()->getNumNoReplyDomainCheckIns() >= MAX_SILENT_DOMAIN_SERVER_CHECK_INS) { - qDebug() << "Exit loop... getInstance()->getNumNoReplyDomainCheckIns() >= MAX_SILENT_DOMAIN_SERVER_CHECK_INS\n"; - break; - } - - // 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(); - } - - // ping our inactive nodes to punch holes with them - nodeList->pingInactiveNodes(); - - if (nodeList->getNodeSocket().hasPendingDatagrams() - && (packetLength = nodeList->getNodeSocket().readDatagram((char*) packetData, MAX_PACKET_SIZE, - senderSockAddr.getAddressPointer(), - senderSockAddr.getPortPointer())) - && packetVersionMatch(packetData)) { - - int numBytesPacketHeader = numBytesForPacketHeader(packetData); - - if (packetData[0] == PACKET_TYPE_VOXEL_QUERY) { - // If we got a PACKET_TYPE_VOXEL_QUERY, then we're talking to an NODE_TYPE_AVATAR, and we - // need to make sure we have it in our nodeList. - QUuid nodeUUID = QUuid::fromRfc4122(QByteArray((char*)packetData + numBytesPacketHeader, - NUM_BYTES_RFC4122_UUID)); - - Node* node = nodeList->nodeWithUUID(nodeUUID); - - if (node) { - nodeList->updateNodeWithData(node, senderSockAddr, packetData, packetLength); - if (!node->getActiveSocket()) { - // we don't have an active socket for this node, but they're talking to us - // this means they've heard from us and can reply, let's assume public is active - node->activatePublicSocket(); - } - VoxelNodeData* nodeData = (VoxelNodeData*) node->getLinkedData(); - if (nodeData && !nodeData->isVoxelSendThreadInitalized()) { - nodeData->initializeVoxelSendThread(this); - } - } - } else if (packetData[0] == PACKET_TYPE_VOXEL_JURISDICTION_REQUEST) { - if (_jurisdictionSender) { - _jurisdictionSender->queueReceivedPacket(senderSockAddr, packetData, packetLength); - } - } else if (_voxelServerPacketProcessor && - (packetData[0] == PACKET_TYPE_SET_VOXEL - || packetData[0] == PACKET_TYPE_SET_VOXEL_DESTRUCTIVE - || packetData[0] == PACKET_TYPE_ERASE_VOXEL - || packetData[0] == PACKET_TYPE_Z_COMMAND)) { - - - const char* messageName; - switch (packetData[0]) { - case PACKET_TYPE_SET_VOXEL: - messageName = "PACKET_TYPE_SET_VOXEL"; - break; - case PACKET_TYPE_SET_VOXEL_DESTRUCTIVE: - messageName = "PACKET_TYPE_SET_VOXEL_DESTRUCTIVE"; - break; - case PACKET_TYPE_ERASE_VOXEL: - messageName = "PACKET_TYPE_ERASE_VOXEL"; - break; - } - int numBytesPacketHeader = numBytesForPacketHeader(packetData); - - if (packetData[0] != PACKET_TYPE_Z_COMMAND) { - unsigned short int sequence = (*((unsigned short int*)(packetData + numBytesPacketHeader))); - uint64_t sentAt = (*((uint64_t*)(packetData + numBytesPacketHeader + sizeof(sequence)))); - uint64_t arrivedAt = usecTimestampNow(); - uint64_t transitTime = arrivedAt - sentAt; - if (wantShowAnimationDebug() || wantsDebugVoxelReceiving()) { - printf("RECEIVE THREAD: got %s - command from client receivedBytes=%ld sequence=%d transitTime=%llu usecs\n", - messageName, - packetLength, sequence, transitTime); - } - } - - _voxelServerPacketProcessor->queueReceivedPacket(senderSockAddr, packetData, packetLength); - } else { - // let processNodeData handle it. - NodeList::getInstance()->processNodeData(senderSockAddr, packetData, packetLength); - } - } + while (!_isFinished) { + QCoreApplication::processEvents(); } // call NodeList::clear() so that all of our node specific objects, including our sending threads, are diff --git a/libraries/voxel-server-library/src/VoxelServer.h b/libraries/voxel-server-library/src/VoxelServer.h index 4aee48e5f1..f4923778c1 100644 --- a/libraries/voxel-server-library/src/VoxelServer.h +++ b/libraries/voxel-server-library/src/VoxelServer.h @@ -14,7 +14,7 @@ #include #include -#include +#include #include #include "civetweb.h" @@ -26,14 +26,13 @@ #include "VoxelServerPacketProcessor.h" /// Handles assignments of type VoxelServer - sending voxels to various clients. -class VoxelServer : public Assignment { +class VoxelServer : public ThreadedAssignment { public: VoxelServer(const unsigned char* dataBuffer, int numBytes); ~VoxelServer(); - /// runs the voxel server assignment - void run(); + /// allows setting of run arguments void setArguments(int argc, char** argv); @@ -59,7 +58,11 @@ public: bool isInitialLoadComplete() const { return (_voxelPersistThread) ? _voxelPersistThread->isInitialLoadComplete() : true; } time_t* getLoadCompleted() { return (_voxelPersistThread) ? _voxelPersistThread->getLoadCompleted() : NULL; } uint64_t getLoadElapsedTime() const { return (_voxelPersistThread) ? _voxelPersistThread->getLoadElapsedTime() : 0; } +public slots: + /// runs the voxel server assignment + void run(); + void processDatagram(const QByteArray& dataByteArray, const HifiSockAddr& senderSockAddr); private: int _argc; const char** _argv; From 330179699799e7f2af3580a51774d439d8d46b07 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 3 Dec 2013 11:20:12 -0800 Subject: [PATCH 19/31] change const HifiSockAddr in DataServerClient to remove error --- interface/src/DataServerClient.cpp | 16 ++++++++++++---- interface/src/DataServerClient.h | 1 + 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/interface/src/DataServerClient.cpp b/interface/src/DataServerClient.cpp index 547b2dcd3f..33fa59e3e4 100644 --- a/interface/src/DataServerClient.cpp +++ b/interface/src/DataServerClient.cpp @@ -24,7 +24,12 @@ const char MULTI_KEY_VALUE_SEPARATOR = '|'; const char DATA_SERVER_HOSTNAME[] = "data.highfidelity.io"; const unsigned short DATA_SERVER_PORT = 3282; -const HifiSockAddr DATA_SERVER_SOCKET = HifiSockAddr(DATA_SERVER_HOSTNAME, DATA_SERVER_PORT); + + +const HifiSockAddr& DataServerClient::dataServerSockAddr() { + static HifiSockAddr dsSockAddr = HifiSockAddr(DATA_SERVER_HOSTNAME, DATA_SERVER_PORT); + return dsSockAddr; +} void DataServerClient::putValueForKey(const QString& key, const char* value) { QString clientString = Application::getInstance()->getProfile()->getUserString(); @@ -58,7 +63,8 @@ void DataServerClient::putValueForKey(const QString& key, const char* value) { // send this put request to the data server NodeList::getInstance()->getNodeSocket().writeDatagram((char*) putPacket, numPacketBytes, - DATA_SERVER_SOCKET.getAddress(), DATA_SERVER_SOCKET.getPort()); + dataServerSockAddr().getAddress(), + dataServerSockAddr().getPort()); } } @@ -98,7 +104,8 @@ void DataServerClient::getValuesForKeysAndUserString(const QStringList& keys, co // send the get to the data server NodeList::getInstance()->getNodeSocket().writeDatagram((char*) getPacket, numPacketBytes, - DATA_SERVER_SOCKET.getAddress(), DATA_SERVER_SOCKET.getPort()); + dataServerSockAddr().getAddress(), + dataServerSockAddr().getPort()); } } @@ -239,6 +246,7 @@ void DataServerClient::resendUnmatchedPackets() { ++mapIterator) { // send the unmatched packet to the data server NodeList::getInstance()->getNodeSocket().writeDatagram((char*) mapIterator->first, mapIterator->second, - DATA_SERVER_SOCKET.getAddress(), DATA_SERVER_SOCKET.getPort()); + dataServerSockAddr().getAddress(), + dataServerSockAddr().getPort()); } } diff --git a/interface/src/DataServerClient.h b/interface/src/DataServerClient.h index 2331cae1e9..b0ccbe13ee 100644 --- a/interface/src/DataServerClient.h +++ b/interface/src/DataServerClient.h @@ -17,6 +17,7 @@ class DataServerClient { public: + static const HifiSockAddr& dataServerSockAddr(); static void putValueForKey(const QString& key, const char* value); static void getClientValueForKey(const QString& key); From 182c69c7b867cedcc45742cca6f8099878f8fbe8 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 3 Dec 2013 11:34:54 -0800 Subject: [PATCH 20/31] re-write Agent to use new QCA infrastructure --- assignment-client/src/Agent.cpp | 83 +++++++++++++-------------------- assignment-client/src/Agent.h | 15 +++--- 2 files changed, 41 insertions(+), 57 deletions(-) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index 24934397ad..700b4e13d0 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -6,7 +6,9 @@ // Copyright (c) 2013 HighFidelity, Inc. All rights reserved. // +#include #include +#include #include #include #include @@ -17,19 +19,12 @@ #include #include "Agent.h" -#include "voxels/VoxelScriptingInterface.h" Agent::Agent(const unsigned char* dataBuffer, int numBytes) : - Assignment(dataBuffer, numBytes), - _shouldStop(false) + ThreadedAssignment(dataBuffer, numBytes) { } - -void Agent::stop() { - _shouldStop = true; -} - QScriptValue vec3toScriptValue(QScriptEngine *engine, const glm::vec3 &vec3) { QScriptValue obj = engine->newObject(); obj.setProperty("x", vec3.x); @@ -44,6 +39,16 @@ void vec3FromScriptValue(const QScriptValue &object, glm::vec3 &vec3) { vec3.z = object.property("z").toVariant().toFloat(); } +void Agent::processDatagram(const QByteArray& dataByteArray, const HifiSockAddr& senderSockAddr) { + if (dataByteArray.data()[0] == PACKET_TYPE_VOXEL_JURISDICTION) { + _voxelScriptingInterface.getJurisdictionListener()->queueReceivedPacket(senderSockAddr, + (unsigned char*) dataByteArray.data(), + dataByteArray.size()); + } else { + NodeList::getInstance()->processNodeData(senderSockAddr, (unsigned char*) dataByteArray.data(), dataByteArray.size()); + } +} + void Agent::run() { NodeList* nodeList = NodeList::getInstance(); nodeList->setOwnerType(NODE_TYPE_AGENT); @@ -76,8 +81,7 @@ void Agent::run() { QScriptValue agentValue = engine.newQObject(this); engine.globalObject().setProperty("Agent", agentValue); - VoxelScriptingInterface voxelScripter; - QScriptValue voxelScripterValue = engine.newQObject(&voxelScripter); + QScriptValue voxelScripterValue = engine.newQObject(&_voxelScriptingInterface); engine.globalObject().setProperty("Voxels", voxelScripterValue); QScriptValue treeScaleValue = engine.newVariant(QVariant(TREE_SCALE)); @@ -86,7 +90,7 @@ void Agent::run() { const unsigned int VISUAL_DATA_CALLBACK_USECS = (1.0 / 60.0) * 1000 * 1000; // let the VoxelPacketSender know how frequently we plan to call it - voxelScripter.getVoxelPacketSender()->setProcessCallIntervalHint(VISUAL_DATA_CALLBACK_USECS); + _voxelScriptingInterface.getVoxelPacketSender()->setProcessCallIntervalHint(VISUAL_DATA_CALLBACK_USECS); qDebug() << "Downloaded script:" << scriptContents << "\n"; QScriptValue result = engine.evaluate(scriptContents); @@ -100,46 +104,40 @@ void Agent::run() { timeval startTime; gettimeofday(&startTime, NULL); - timeval lastDomainServerCheckIn = {}; - - - HifiSockAddr senderSockAddr; - unsigned char receivedData[MAX_PACKET_SIZE]; - ssize_t receivedBytes; - int thisFrame = 0; - NodeList::getInstance()->startSilentNodeRemovalThread(); + QTimer* domainServerTimer = new QTimer(this); + connect(domainServerTimer, SIGNAL(timeout()), this, SLOT(checkInWithDomainServerOrExit())); + domainServerTimer->start(DOMAIN_SERVER_CHECK_IN_USECS / 1000); - while (!_shouldStop) { - - // if we're not hearing from the domain-server we should stop running - if (NodeList::getInstance()->getNumNoReplyDomainCheckIns() == MAX_SILENT_DOMAIN_SERVER_CHECK_INS) { - break; - } - - // 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(); - } + QTimer* silentNodeTimer = new QTimer(this); + connect(silentNodeTimer, SIGNAL(timeout()), nodeList, SLOT(removeSilentNodes())); + silentNodeTimer->start(NODE_SILENCE_THRESHOLD_USECS / 1000); + + QTimer* pingNodesTimer = new QTimer(this); + connect(pingNodesTimer, SIGNAL(timeout()), nodeList, SLOT(pingInactiveNodes())); + pingNodesTimer->start(PING_INACTIVE_NODE_INTERVAL_USECS / 1000); + + while (!_isFinished) { int usecToSleep = usecTimestamp(&startTime) + (thisFrame++ * VISUAL_DATA_CALLBACK_USECS) - usecTimestampNow(); if (usecToSleep > 0) { usleep(usecToSleep); } - if (voxelScripter.getVoxelPacketSender()->voxelServersExist()) { + QCoreApplication::processEvents(); + + if (_voxelScriptingInterface.getVoxelPacketSender()->voxelServersExist()) { timeval thisSend = {}; gettimeofday(&thisSend, NULL); // allow the scripter's call back to setup visual data emit willSendVisualDataCallback(); // release the queue of edit voxel messages. - voxelScripter.getVoxelPacketSender()->releaseQueuedMessages(); + _voxelScriptingInterface.getVoxelPacketSender()->releaseQueuedMessages(); // since we're in non-threaded mode, call process so that the packets are sent - voxelScripter.getVoxelPacketSender()->process(); + _voxelScriptingInterface.getVoxelPacketSender()->process(); } if (engine.hasUncaughtException()) { @@ -147,21 +145,6 @@ void Agent::run() { qDebug() << "Uncaught exception at line" << line << ":" << engine.uncaughtException().toString() << "\n"; } - while (nodeList->getNodeSocket().hasPendingDatagrams() && - (receivedBytes = nodeList->getNodeSocket().readDatagram((char*) receivedBytes, - MAX_PACKET_SIZE, - senderSockAddr.getAddressPointer(), - senderSockAddr.getPortPointer())) - && packetVersionMatch(receivedData)) { - if (receivedData[0] == PACKET_TYPE_VOXEL_JURISDICTION) { - voxelScripter.getJurisdictionListener()->queueReceivedPacket(senderSockAddr, - receivedData, - receivedBytes); - } else { - NodeList::getInstance()->processNodeData(senderSockAddr, receivedData, receivedBytes); - } - } + } - - NodeList::getInstance()->stopSilentNodeRemovalThread(); } diff --git a/assignment-client/src/Agent.h b/assignment-client/src/Agent.h index 2ad7eba1e6..5f0865e420 100644 --- a/assignment-client/src/Agent.h +++ b/assignment-client/src/Agent.h @@ -15,23 +15,24 @@ #include #include -#include +#include -class Agent : public Assignment { +#include "voxels/VoxelScriptingInterface.h" + +class Agent : public ThreadedAssignment { Q_OBJECT public: Agent(const unsigned char* dataBuffer, int numBytes); - void run(); public slots: - void stop(); + void run(); + + void processDatagram(const QByteArray& dataByteArray, const HifiSockAddr& senderSockAddr); signals: void willSendAudioDataCallback(); void willSendVisualDataCallback(); private: - static QScriptValue AudioInjectorConstructor(QScriptContext *context, QScriptEngine *engine); - - bool volatile _shouldStop; + VoxelScriptingInterface _voxelScriptingInterface; }; #endif /* defined(__hifi__Agent__) */ From 5143c68b91e39aa84f6acfba5ab83377cea334bb Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 3 Dec 2013 12:09:47 -0800 Subject: [PATCH 21/31] fix packet sending from VoxelScriptingInterface --- assignment-client/src/Agent.cpp | 4 +--- assignment-client/src/AssignmentClient.cpp | 12 ++++++------ .../src/voxels/VoxelScriptingInterface.cpp | 10 ++++------ libraries/voxel-server-library/src/VoxelServer.cpp | 3 +-- libraries/voxels/src/VoxelEditPacketSender.cpp | 1 + 5 files changed, 13 insertions(+), 17 deletions(-) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index 700b4e13d0..9d0d615946 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -127,9 +127,7 @@ void Agent::run() { QCoreApplication::processEvents(); - if (_voxelScriptingInterface.getVoxelPacketSender()->voxelServersExist()) { - timeval thisSend = {}; - gettimeofday(&thisSend, NULL); + if (_voxelScriptingInterface.getVoxelPacketSender()->voxelServersExist()) { // allow the scripter's call back to setup visual data emit willSendVisualDataCallback(); diff --git a/assignment-client/src/AssignmentClient.cpp b/assignment-client/src/AssignmentClient.cpp index f20e0da2a5..a61a1e7491 100644 --- a/assignment-client/src/AssignmentClient.cpp +++ b/assignment-client/src/AssignmentClient.cpp @@ -74,7 +74,12 @@ void AssignmentClient::readPendingDatagrams() { senderSockAddr.getPortPointer())) && packetVersionMatch(packetData)) { - if (packetData[0] == PACKET_TYPE_DEPLOY_ASSIGNMENT || packetData[0] == PACKET_TYPE_CREATE_ASSIGNMENT) { + if (_currentAssignment) { + // have the threaded current assignment handle this datagram + QMetaObject::invokeMethod(_currentAssignment, "processDatagram", Qt::QueuedConnection, + Q_ARG(const QByteArray&, QByteArray((char*) packetData, receivedBytes)), + Q_ARG(const HifiSockAddr&, senderSockAddr)); + } else if (packetData[0] == PACKET_TYPE_DEPLOY_ASSIGNMENT || packetData[0] == PACKET_TYPE_CREATE_ASSIGNMENT) { if (_currentAssignment) { qDebug() << "Dropping received assignment since we are currently running one.\n"; @@ -110,11 +115,6 @@ void AssignmentClient::readPendingDatagrams() { qDebug("Received a bad destination socket for assignment.\n"); } } - } else if (_currentAssignment) { - // have the threaded current assignment handle this datagram - QMetaObject::invokeMethod(_currentAssignment, "processDatagram", Qt::QueuedConnection, - Q_ARG(const QByteArray&, QByteArray((char*) packetData, receivedBytes)), - Q_ARG(const HifiSockAddr&, senderSockAddr)); } else { // have the NodeList attempt to handle it nodeList->processNodeData(senderSockAddr, packetData, receivedBytes); diff --git a/assignment-client/src/voxels/VoxelScriptingInterface.cpp b/assignment-client/src/voxels/VoxelScriptingInterface.cpp index b967c23187..1801c621c4 100644 --- a/assignment-client/src/voxels/VoxelScriptingInterface.cpp +++ b/assignment-client/src/voxels/VoxelScriptingInterface.cpp @@ -27,13 +27,11 @@ void VoxelScriptingInterface::queueVoxelAdd(float x, float y, float z, float sca void VoxelScriptingInterface::queueDestructiveVoxelAdd(float x, float y, float z, float scale, uchar red, uchar green, uchar blue) { -// // setup a VoxelDetail struct with the data -// VoxelDetail addVoxelDetail = {x, y, z, scale, red, green, blue}; -// -// // queue the destructive add -// queueVoxelAdd(PACKET_TYPE_SET_VOXEL_DESTRUCTIVE, addVoxelDetail); + // setup a VoxelDetail struct with the data + VoxelDetail addVoxelDetail = {x, y, z, scale, red, green, blue}; - _voxelTree.createVoxel(x, y, z, scale, red, green, blue); + // queue the destructive add + queueVoxelAdd(PACKET_TYPE_SET_VOXEL_DESTRUCTIVE, addVoxelDetail); } void VoxelScriptingInterface::queueVoxelDelete(float x, float y, float z, float scale) { diff --git a/libraries/voxel-server-library/src/VoxelServer.cpp b/libraries/voxel-server-library/src/VoxelServer.cpp index 2653d63ccf..bbf0c2d54e 100644 --- a/libraries/voxel-server-library/src/VoxelServer.cpp +++ b/libraries/voxel-server-library/src/VoxelServer.cpp @@ -523,13 +523,12 @@ void VoxelServer::processDatagram(const QByteArray& dataByteArray, const HifiSoc uint64_t sentAt = (*((uint64_t*)(dataByteArray.data() + numBytesPacketHeader + sizeof(sequence)))); uint64_t arrivedAt = usecTimestampNow(); uint64_t transitTime = arrivedAt - sentAt; - if (wantShowAnimationDebug() || wantsDebugVoxelReceiving()) { + if (true) { printf("RECEIVE THREAD: got %s - command from client receivedBytes=%d sequence=%d transitTime=%llu usecs\n", messageName, dataByteArray.size(), sequence, transitTime); } } - _voxelServerPacketProcessor->queueReceivedPacket(senderSockAddr, (unsigned char*) dataByteArray.data(), dataByteArray.size()); } else { diff --git a/libraries/voxels/src/VoxelEditPacketSender.cpp b/libraries/voxels/src/VoxelEditPacketSender.cpp index bfc42da63f..823b7343d0 100644 --- a/libraries/voxels/src/VoxelEditPacketSender.cpp +++ b/libraries/voxels/src/VoxelEditPacketSender.cpp @@ -313,6 +313,7 @@ void VoxelEditPacketSender::releaseQueuedMessages() { void VoxelEditPacketSender::releaseQueuedPacket(EditPacketBuffer& packetBuffer) { if (packetBuffer._currentSize > 0 && packetBuffer._currentType != PACKET_TYPE_UNKNOWN) { + qDebug() << "queueing packet to node\n"; queuePacketToNode(packetBuffer._nodeUUID, &packetBuffer._currentBuffer[0], packetBuffer._currentSize); } packetBuffer._currentSize = 0; From bdf9f9eb22939b2f381182ed38f5ee7ee9b1f791 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 3 Dec 2013 12:11:31 -0800 Subject: [PATCH 22/31] remove extra debugging line --- libraries/voxels/src/VoxelEditPacketSender.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/voxels/src/VoxelEditPacketSender.cpp b/libraries/voxels/src/VoxelEditPacketSender.cpp index 823b7343d0..bfc42da63f 100644 --- a/libraries/voxels/src/VoxelEditPacketSender.cpp +++ b/libraries/voxels/src/VoxelEditPacketSender.cpp @@ -313,7 +313,6 @@ void VoxelEditPacketSender::releaseQueuedMessages() { void VoxelEditPacketSender::releaseQueuedPacket(EditPacketBuffer& packetBuffer) { if (packetBuffer._currentSize > 0 && packetBuffer._currentType != PACKET_TYPE_UNKNOWN) { - qDebug() << "queueing packet to node\n"; queuePacketToNode(packetBuffer._nodeUUID, &packetBuffer._currentBuffer[0], packetBuffer._currentSize); } packetBuffer._currentSize = 0; From 3d14fba7abfbf8f85e097b6f941d7666b72d87d6 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 3 Dec 2013 12:14:24 -0800 Subject: [PATCH 23/31] have AssignmentFactory return a ThreadedAssignment --- assignment-client/src/AssignmentClient.cpp | 2 +- assignment-client/src/AssignmentFactory.cpp | 4 ++-- assignment-client/src/AssignmentFactory.h | 4 ++-- libraries/voxel-server-library/src/VoxelServer.cpp | 3 --- 4 files changed, 5 insertions(+), 8 deletions(-) diff --git a/assignment-client/src/AssignmentClient.cpp b/assignment-client/src/AssignmentClient.cpp index a61a1e7491..87f6037e9e 100644 --- a/assignment-client/src/AssignmentClient.cpp +++ b/assignment-client/src/AssignmentClient.cpp @@ -85,7 +85,7 @@ void AssignmentClient::readPendingDatagrams() { qDebug() << "Dropping received assignment since we are currently running one.\n"; } else { // construct the deployed assignment from the packet data - _currentAssignment = (ThreadedAssignment*) AssignmentFactory::unpackAssignment(packetData, receivedBytes); + _currentAssignment = AssignmentFactory::unpackAssignment(packetData, receivedBytes); qDebug() << "Received an assignment -" << *_currentAssignment << "\n"; diff --git a/assignment-client/src/AssignmentFactory.cpp b/assignment-client/src/AssignmentFactory.cpp index a3aa657943..aa173f920f 100644 --- a/assignment-client/src/AssignmentFactory.cpp +++ b/assignment-client/src/AssignmentFactory.cpp @@ -15,7 +15,7 @@ #include "AssignmentFactory.h" -Assignment* AssignmentFactory::unpackAssignment(const unsigned char* dataBuffer, int numBytes) { +ThreadedAssignment* AssignmentFactory::unpackAssignment(const unsigned char* dataBuffer, int numBytes) { int headerBytes = numBytesForPacketHeader(dataBuffer); Assignment::Type assignmentType = Assignment::AllTypes; @@ -31,6 +31,6 @@ Assignment* AssignmentFactory::unpackAssignment(const unsigned char* dataBuffer, case Assignment::VoxelServerType: return new VoxelServer(dataBuffer, numBytes); default: - return new Assignment(dataBuffer, numBytes); + return NULL; } } \ No newline at end of file diff --git a/assignment-client/src/AssignmentFactory.h b/assignment-client/src/AssignmentFactory.h index 8adadb07ed..4605d961ec 100644 --- a/assignment-client/src/AssignmentFactory.h +++ b/assignment-client/src/AssignmentFactory.h @@ -9,11 +9,11 @@ #ifndef __hifi__AssignmentFactory__ #define __hifi__AssignmentFactory__ -#include "Assignment.h" +#include class AssignmentFactory { public: - static Assignment* unpackAssignment(const unsigned char* dataBuffer, int numBytes); + static ThreadedAssignment* unpackAssignment(const unsigned char* dataBuffer, int numBytes); }; #endif /* defined(__hifi__AssignmentFactory__) */ diff --git a/libraries/voxel-server-library/src/VoxelServer.cpp b/libraries/voxel-server-library/src/VoxelServer.cpp index bbf0c2d54e..ebe298ccf1 100644 --- a/libraries/voxel-server-library/src/VoxelServer.cpp +++ b/libraries/voxel-server-library/src/VoxelServer.cpp @@ -692,9 +692,6 @@ void VoxelServer::run() { } HifiSockAddr senderSockAddr; - - unsigned char* packetData = new unsigned char[MAX_PACKET_SIZE]; - ssize_t packetLength; // set up our jurisdiction broadcaster... _jurisdictionSender = new JurisdictionSender(_jurisdiction); From 8fbd1e4cfbef4dc0197f37436e0f20c76b5a5c85 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 3 Dec 2013 12:28:44 -0800 Subject: [PATCH 24/31] repairs after merge with upstream master --- interface/src/Application.cpp | 47 ++++++----- interface/src/Application.h | 2 + interface/src/VoxelPacketProcessor.cpp | 12 +-- interface/src/VoxelPacketProcessor.h | 2 +- .../src/VoxelSendThread.cpp | 54 ++++++++++++- .../voxel-server-library/src/VoxelServer.cpp | 81 +++++++++---------- .../src/VoxelServerPacketProcessor.cpp | 29 ------- 7 files changed, 124 insertions(+), 103 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 28641e7649..f1cfe01a90 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3934,26 +3934,15 @@ bool Application::maybeEditVoxelUnderCursor() { if (Menu::getInstance()->isOptionChecked(MenuOption::VoxelAddMode) || Menu::getInstance()->isOptionChecked(MenuOption::VoxelColorMode)) { if (_mouseVoxel.s != 0) { - PACKET_TYPE message = Menu::getInstance()->isOptionChecked(MenuOption::DestructiveAddVoxel) - ? PACKET_TYPE_SET_VOXEL_DESTRUCTIVE - : PACKET_TYPE_SET_VOXEL; - _voxelEditSender.sendVoxelEditMessage(message, _mouseVoxel); - - // create the voxel locally so it appears immediately - _voxels.createVoxel(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s, - _mouseVoxel.red, _mouseVoxel.green, _mouseVoxel.blue, - Menu::getInstance()->isOptionChecked(MenuOption::DestructiveAddVoxel)); - - // Implement voxel fade effect - VoxelFade fade(VoxelFade::FADE_OUT, 1.0f, 1.0f, 1.0f); - const float VOXEL_BOUNDS_ADJUST = 0.01f; - float slightlyBigger = _mouseVoxel.s * VOXEL_BOUNDS_ADJUST; - fade.voxelDetails.x = _mouseVoxel.x - slightlyBigger; - fade.voxelDetails.y = _mouseVoxel.y - slightlyBigger; - fade.voxelDetails.z = _mouseVoxel.z - slightlyBigger; - fade.voxelDetails.s = _mouseVoxel.s + slightlyBigger + slightlyBigger; - _voxelFades.push_back(fade); - + makeVoxel(glm::vec3(_mouseVoxel.x * TREE_SCALE, + _mouseVoxel.y * TREE_SCALE, + _mouseVoxel.z * TREE_SCALE), + _mouseVoxel.s * TREE_SCALE, + _mouseVoxel.red, + _mouseVoxel.green, + _mouseVoxel.blue, + Menu::getInstance()->isOptionChecked(MenuOption::DestructiveAddVoxel)); + // remember the position for drag detection _justEditedVoxel = true; @@ -4139,6 +4128,24 @@ void Application::nodeKilled(Node* node) { } } +void Application::trackIncomingVoxelPacket(unsigned char* messageData, ssize_t messageLength, + const HifiSockAddr& senderSockAddr, bool wasStatsPacket) { + + // Attempt to identify the sender from it's address. + Node* voxelServer = NodeList::getInstance()->nodeWithAddress(senderSockAddr); + if (voxelServer) { + QUuid nodeUUID = voxelServer->getUUID(); + + // now that we know the node ID, let's add these stats to the stats for that node... + _voxelSceneStatsLock.lockForWrite(); + if (_voxelServerSceneStats.find(nodeUUID) != _voxelServerSceneStats.end()) { + VoxelSceneStats& stats = _voxelServerSceneStats[nodeUUID]; + stats.trackIncomingVoxelPacket(messageData, messageLength, wasStatsPacket); + } + _voxelSceneStatsLock.unlock(); + } +} + int Application::parseVoxelStats(unsigned char* messageData, ssize_t messageLength, const HifiSockAddr& senderSockAddr) { // But, also identify the sender, and keep track of the contained jurisdiction root for this server diff --git a/interface/src/Application.h b/interface/src/Application.h index fd35d547b9..0f52327197 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -462,6 +462,8 @@ private: PieMenu _pieMenu; int parseVoxelStats(unsigned char* messageData, ssize_t messageLength, const HifiSockAddr& senderAddress); + void trackIncomingVoxelPacket(unsigned char* messageData, ssize_t messageLength, + const HifiSockAddr& senderSockAddr, bool wasStatsPacket); NodeToJurisdictionMap _voxelServerJurisdictions; NodeToVoxelSceneStats _voxelServerSceneStats; diff --git a/interface/src/VoxelPacketProcessor.cpp b/interface/src/VoxelPacketProcessor.cpp index ded4ec0183..a591fbdbaa 100644 --- a/interface/src/VoxelPacketProcessor.cpp +++ b/interface/src/VoxelPacketProcessor.cpp @@ -14,7 +14,7 @@ #include "Menu.h" #include "VoxelPacketProcessor.h" -void VoxelPacketProcessor::processPacket(const HifiSockAddr& senderAddress, unsigned char* packetData, ssize_t packetLength) { +void VoxelPacketProcessor::processPacket(const HifiSockAddr& senderSockAddr, unsigned char* packetData, ssize_t packetLength) { PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "VoxelPacketProcessor::processPacket()"); @@ -39,7 +39,7 @@ void VoxelPacketProcessor::processPacket(const HifiSockAddr& senderAddress, unsi // then process any remaining bytes as if it was another packet if (packetData[0] == PACKET_TYPE_VOXEL_STATS) { - int statsMessageLength = app->parseVoxelStats(packetData, messageLength, senderAddress); + int statsMessageLength = app->parseVoxelStats(packetData, messageLength, senderSockAddr); wasStatsPacket = true; if (messageLength > statsMessageLength) { packetData += statsMessageLength; @@ -54,10 +54,12 @@ void VoxelPacketProcessor::processPacket(const HifiSockAddr& senderAddress, unsi } // fall through to piggyback message if (Menu::getInstance()->isOptionChecked(MenuOption::Voxels)) { - Node* voxelServer = NodeList::getInstance()->nodeWithAddress(senderAddress); - if (voxelServer && *voxelServer->getActiveSocket() == senderAddress) { + app->trackIncomingVoxelPacket(packetData, messageLength, senderSockAddr, wasStatsPacket); + + Node* voxelServer = NodeList::getInstance()->nodeWithAddress(senderSockAddr); + if (voxelServer && *voxelServer->getActiveSocket() == senderSockAddr) { if (packetData[0] == PACKET_TYPE_ENVIRONMENT_DATA) { - app->_environment.parseData(senderAddress, packetData, messageLength); + app->_environment.parseData(senderSockAddr, packetData, messageLength); } else { app->_voxels.setDataSourceUUID(voxelServer->getUUID()); app->_voxels.parseData(packetData, messageLength); diff --git a/interface/src/VoxelPacketProcessor.h b/interface/src/VoxelPacketProcessor.h index 4420ccc6cf..e8e77e6895 100644 --- a/interface/src/VoxelPacketProcessor.h +++ b/interface/src/VoxelPacketProcessor.h @@ -17,6 +17,6 @@ /// the user is responsible for reading inbound packets and adding them to the processing queue by calling queueReceivedPacket() class VoxelPacketProcessor : public ReceivedPacketProcessor { protected: - virtual void processPacket(const HifiSockAddr& senderAddress, unsigned char* packetData, ssize_t packetLength); + virtual void processPacket(const HifiSockAddr& senderSockAddr, unsigned char* packetData, ssize_t packetLength); }; #endif // __shared__VoxelPacketProcessor__ diff --git a/libraries/voxel-server-library/src/VoxelSendThread.cpp b/libraries/voxel-server-library/src/VoxelSendThread.cpp index 7cce32aa85..cb9dae0693 100644 --- a/libraries/voxel-server-library/src/VoxelSendThread.cpp +++ b/libraries/voxel-server-library/src/VoxelSendThread.cpp @@ -148,11 +148,27 @@ int VoxelSendThread::handlePacketSend(Node* node, VoxelNodeData* nodeData, int& NodeList::getInstance()->getNodeSocket().writeDatagram((char*) statsMessage, statsMessageLength, node->getActiveSocket()->getAddress(), node->getActiveSocket()->getPort()); + packetSent = true; } else { // not enough room in the packet, send two packets NodeList::getInstance()->getNodeSocket().writeDatagram((char*) statsMessage, statsMessageLength, node->getActiveSocket()->getAddress(), node->getActiveSocket()->getPort()); + + // since a stats message is only included on end of scene, don't consider any of these bytes "wasted", since + // there was nothing else to send. + int thisWastedBytes = 0; + _totalWastedBytes += thisWastedBytes; + _totalBytes += statsMessageLength; + _totalPackets++; + if (debug) { + qDebug("Sending separate stats packet at %llu [%llu]: size:%d [%llu] wasted bytes:%d [%llu]\n", + now, + _totalPackets, + statsMessageLength, _totalBytes, + thisWastedBytes, _totalWastedBytes); + } + trueBytesSent += statsMessageLength; truePacketsSent++; packetsSent++; @@ -160,13 +176,43 @@ int VoxelSendThread::handlePacketSend(Node* node, VoxelNodeData* nodeData, int& NodeList::getInstance()->getNodeSocket().writeDatagram((char*) nodeData->getPacket(), nodeData->getPacketLength(), node->getActiveSocket()->getAddress(), node->getActiveSocket()->getPort()); + + packetSent = true; + + thisWastedBytes = MAX_PACKET_SIZE - nodeData->getPacketLength(); + _totalWastedBytes += thisWastedBytes; + _totalBytes += nodeData->getPacketLength(); + _totalPackets++; + if (debug) { + qDebug("Sending packet at %llu [%llu]: sequence: %d size:%d [%llu] wasted bytes:%d [%llu]\n", + now, + _totalPackets, + sequence, nodeData->getPacketLength(), _totalBytes, + thisWastedBytes, _totalWastedBytes); + } } nodeData->stats.markAsSent(); } else { - // just send the voxel packet - NodeList::getInstance()->getNodeSocket().writeDatagram((char*) nodeData->getPacket(), nodeData->getPacketLength(), - node->getActiveSocket()->getAddress(), - node->getActiveSocket()->getPort()); + // If there's actually a packet waiting, then send it. + if (nodeData->isPacketWaiting()) { + // just send the voxel packet + NodeList::getInstance()->getNodeSocket().writeDatagram((char*) nodeData->getPacket(), nodeData->getPacketLength(), + node->getActiveSocket()->getAddress(), + node->getActiveSocket()->getPort()); + packetSent = true; + + int thisWastedBytes = MAX_PACKET_SIZE - nodeData->getPacketLength(); + _totalWastedBytes += thisWastedBytes; + _totalBytes += nodeData->getPacketLength(); + _totalPackets++; + if (debug) { + qDebug("Sending packet at %llu [%llu]: sequence:%d size:%d [%llu] wasted bytes:%d [%llu]\n", + now, + _totalPackets, + sequence, nodeData->getPacketLength(), _totalBytes, + thisWastedBytes, _totalWastedBytes); + } + } } // remember to track our stats if (packetSent) { diff --git a/libraries/voxel-server-library/src/VoxelServer.cpp b/libraries/voxel-server-library/src/VoxelServer.cpp index e042c73fd3..6543421caf 100644 --- a/libraries/voxel-server-library/src/VoxelServer.cpp +++ b/libraries/voxel-server-library/src/VoxelServer.cpp @@ -501,18 +501,24 @@ void VoxelServer::parsePayload() { void VoxelServer::processDatagram(const QByteArray& dataByteArray, const HifiSockAddr& senderSockAddr) { NodeList* nodeList = NodeList::getInstance(); - int numBytesPacketHeader = numBytesForPacketHeader((unsigned char*)dataByteArray.data()); - - if (dataByteArray.data()[0] == PACKET_TYPE_VOXEL_QUERY) { + if (dataByteArray[0] == PACKET_TYPE_VOXEL_QUERY) { + bool debug = false; + if (debug) { + qDebug("Got PACKET_TYPE_VOXEL_QUERY at %llu.\n", usecTimestampNow()); + } + + int numBytesPacketHeader = numBytesForPacketHeader((unsigned char*) dataByteArray.data()); + // If we got a PACKET_TYPE_VOXEL_QUERY, then we're talking to an NODE_TYPE_AVATAR, and we // need to make sure we have it in our nodeList. - QUuid nodeUUID = QUuid::fromRfc4122(dataByteArray.mid(numBytesForPacketHeader((unsigned char*) dataByteArray.data()), + QUuid nodeUUID = QUuid::fromRfc4122(dataByteArray.mid(numBytesPacketHeader, NUM_BYTES_RFC4122_UUID)); Node* node = nodeList->nodeWithUUID(nodeUUID); if (node) { - nodeList->updateNodeWithData(node, senderSockAddr, (unsigned char*) dataByteArray.data(), dataByteArray.size()); + nodeList->updateNodeWithData(node, senderSockAddr, (unsigned char *) dataByteArray.data(), + dataByteArray.size()); if (!node->getActiveSocket()) { // we don't have an active socket for this node, but they're talking to us // this means they've heard from us and can reply, let's assume public is active @@ -523,49 +529,36 @@ void VoxelServer::processDatagram(const QByteArray& dataByteArray, const HifiSoc nodeData->initializeVoxelSendThread(this); } } - } else if (dataByteArray.data()[0] == PACKET_TYPE_VOXEL_JURISDICTION_REQUEST) { + } else if (dataByteArray[0] == PACKET_TYPE_VOXEL_JURISDICTION_REQUEST) { if (_jurisdictionSender) { - _jurisdictionSender->queueReceivedPacket(senderSockAddr, - (unsigned char*) dataByteArray.data(), dataByteArray.size()); + _jurisdictionSender->queueReceivedPacket(senderSockAddr, (unsigned char*) dataByteArray.data(), + dataByteArray.size()); } } else if (_voxelServerPacketProcessor && - (dataByteArray.data()[0] == PACKET_TYPE_SET_VOXEL - || dataByteArray.data()[0] == PACKET_TYPE_SET_VOXEL_DESTRUCTIVE - || dataByteArray.data()[0] == PACKET_TYPE_ERASE_VOXEL - || dataByteArray.data()[0] == PACKET_TYPE_Z_COMMAND)) { + (dataByteArray[0] == PACKET_TYPE_SET_VOXEL + || dataByteArray[0] == PACKET_TYPE_SET_VOXEL_DESTRUCTIVE + || dataByteArray[0] == PACKET_TYPE_ERASE_VOXEL)) { - const char* messageName; - switch (dataByteArray.data()[0]) { - case PACKET_TYPE_SET_VOXEL: - messageName = "PACKET_TYPE_SET_VOXEL"; - break; - case PACKET_TYPE_SET_VOXEL_DESTRUCTIVE: - messageName = "PACKET_TYPE_SET_VOXEL_DESTRUCTIVE"; - break; - case PACKET_TYPE_ERASE_VOXEL: - messageName = "PACKET_TYPE_ERASE_VOXEL"; - break; - } - - if (dataByteArray.data()[0] != PACKET_TYPE_Z_COMMAND) { - unsigned short int sequence = (*((unsigned short int*)(dataByteArray.data() + numBytesPacketHeader))); - uint64_t sentAt = (*((uint64_t*)(dataByteArray.data() + numBytesPacketHeader + sizeof(sequence)))); - uint64_t arrivedAt = usecTimestampNow(); - uint64_t transitTime = arrivedAt - sentAt; - if (true) { - printf("RECEIVE THREAD: got %s - command from client receivedBytes=%d sequence=%d transitTime=%llu usecs\n", - messageName, - dataByteArray.size(), sequence, transitTime); - } - } - _voxelServerPacketProcessor->queueReceivedPacket(senderSockAddr, - (unsigned char*) dataByteArray.data(), dataByteArray.size()); - } else { - // let processNodeData handle it. - NodeList::getInstance()->processNodeData(senderSockAddr, - (unsigned char*) dataByteArray.data(), - dataByteArray.size()); - } + + const char* messageName; + switch (dataByteArray[0]) { + case PACKET_TYPE_SET_VOXEL: + messageName = "PACKET_TYPE_SET_VOXEL"; + break; + case PACKET_TYPE_SET_VOXEL_DESTRUCTIVE: + messageName = "PACKET_TYPE_SET_VOXEL_DESTRUCTIVE"; + break; + case PACKET_TYPE_ERASE_VOXEL: + messageName = "PACKET_TYPE_ERASE_VOXEL"; + break; + } + _voxelServerPacketProcessor->queueReceivedPacket(senderSockAddr, (unsigned char*) dataByteArray.data(), + dataByteArray.size()); + } else { + // let processNodeData handle it. + NodeList::getInstance()->processNodeData(senderSockAddr, (unsigned char*) dataByteArray.data(), + dataByteArray.size()); + } } //int main(int argc, const char * argv[]) { diff --git a/libraries/voxel-server-library/src/VoxelServerPacketProcessor.cpp b/libraries/voxel-server-library/src/VoxelServerPacketProcessor.cpp index 46cea75212..abd8705479 100644 --- a/libraries/voxel-server-library/src/VoxelServerPacketProcessor.cpp +++ b/libraries/voxel-server-library/src/VoxelServerPacketProcessor.cpp @@ -170,35 +170,6 @@ void VoxelServerPacketProcessor::processPacket(const HifiSockAddr& senderSockAdd _myServer->getServerTree().processRemoveVoxelBitstream((unsigned char*)packetData, packetLength); _myServer->getServerTree().unlock(); - // Make sure our Node and NodeList knows we've heard from this node. - Node* node = NodeList::getInstance()->nodeWithAddress(senderSockAddr); - if (node) { - node->setLastHeardMicrostamp(usecTimestampNow()); - } - } else if (packetData[0] == PACKET_TYPE_Z_COMMAND) { - - // the Z command is a special command that allows the sender to send the voxel server high level semantic - // requests, like erase all, or add sphere scene - - char* command = (char*) &packetData[numBytesPacketHeader]; // start of the command - int commandLength = strlen(command); // commands are null terminated strings - int totalLength = numBytesPacketHeader + commandLength + 1; // 1 for null termination - printf("got Z message len(%ld)= %s\n", packetLength, command); - bool rebroadcast = true; // by default rebroadcast - - while (totalLength <= packetLength) { - if (strcmp(command, TEST_COMMAND) == 0) { - printf("got Z message == a message, nothing to do, just report\n"); - } - totalLength += commandLength + 1; // 1 for null termination - } - - if (rebroadcast) { - // 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::getInstance()->broadcastToNodes(packetData, packetLength, &NODE_TYPE_AGENT, 1); - } - // Make sure our Node and NodeList knows we've heard from this node. Node* node = NodeList::getInstance()->nodeWithAddress(senderSockAddr); if (node) { From 969f782a9b18b5dd68819105874d0c4bba274169 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 3 Dec 2013 12:29:31 -0800 Subject: [PATCH 25/31] simplify index access of QByteArray in processDatagram --- assignment-client/src/Agent.cpp | 2 +- assignment-client/src/audio/AudioMixer.cpp | 6 +++--- assignment-client/src/avatars/AvatarMixer.cpp | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index 9d0d615946..95c3f91311 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -40,7 +40,7 @@ void vec3FromScriptValue(const QScriptValue &object, glm::vec3 &vec3) { } void Agent::processDatagram(const QByteArray& dataByteArray, const HifiSockAddr& senderSockAddr) { - if (dataByteArray.data()[0] == PACKET_TYPE_VOXEL_JURISDICTION) { + if (dataByteArray[0] == PACKET_TYPE_VOXEL_JURISDICTION) { _voxelScriptingInterface.getJurisdictionListener()->queueReceivedPacket(senderSockAddr, (unsigned char*) dataByteArray.data(), dataByteArray.size()); diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index edc02ec161..08b5668389 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -225,9 +225,9 @@ void AudioMixer::prepareMixForListeningNode(Node* node) { void AudioMixer::processDatagram(const QByteArray& dataByteArray, const HifiSockAddr& senderSockAddr) { // pull any new audio data from nodes off of the network stack - if (dataByteArray.data()[0] == PACKET_TYPE_MICROPHONE_AUDIO_NO_ECHO - || dataByteArray.data()[0] == PACKET_TYPE_MICROPHONE_AUDIO_WITH_ECHO - || dataByteArray.data()[0] == PACKET_TYPE_INJECT_AUDIO) { + if (dataByteArray[0] == PACKET_TYPE_MICROPHONE_AUDIO_NO_ECHO + || dataByteArray[0] == PACKET_TYPE_MICROPHONE_AUDIO_WITH_ECHO + || dataByteArray[0] == PACKET_TYPE_INJECT_AUDIO) { QUuid nodeUUID = QUuid::fromRfc4122(dataByteArray.mid(numBytesForPacketHeader((unsigned char*) dataByteArray.data()), NUM_BYTES_RFC4122_UUID)); diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index 6235bbd81d..4fd46e37f6 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -115,7 +115,7 @@ void AvatarMixer::processDatagram(const QByteArray& dataByteArray, const HifiSoc NodeList* nodeList = NodeList::getInstance(); - switch (dataByteArray.data()[0]) { + switch (dataByteArray[0]) { case PACKET_TYPE_HEAD_DATA: { QUuid nodeUUID = QUuid::fromRfc4122(dataByteArray.mid(numBytesForPacketHeader((unsigned char*) dataByteArray.data()), NUM_BYTES_RFC4122_UUID)); From da580ecbaf43e10cb25a508208d1f4ee76f0e5b6 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 3 Dec 2013 12:31:39 -0800 Subject: [PATCH 26/31] fix inclusion of QThread in Assignment --- assignment-client/src/AssignmentClient.cpp | 1 + libraries/shared/src/Assignment.h | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/assignment-client/src/AssignmentClient.cpp b/assignment-client/src/AssignmentClient.cpp index 87f6037e9e..fff24a51a3 100644 --- a/assignment-client/src/AssignmentClient.cpp +++ b/assignment-client/src/AssignmentClient.cpp @@ -6,6 +6,7 @@ // Copyright (c) 2013 HighFidelity, Inc. All rights reserved. // +#include #include #include diff --git a/libraries/shared/src/Assignment.h b/libraries/shared/src/Assignment.h index d862fda859..ec7ae7f74f 100644 --- a/libraries/shared/src/Assignment.h +++ b/libraries/shared/src/Assignment.h @@ -11,7 +11,6 @@ #include -#include #include #include "NodeList.h" From 8fdd78dc263850ddf9baaffcfa823aef90a31a13 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Tue, 3 Dec 2013 16:25:23 -0800 Subject: [PATCH 27/31] Added drum sounds and voxel collision detection --- interface/src/Audio.cpp | 2 +- interface/src/VoxelSystem.cpp | 32 ++++++++ interface/src/VoxelSystem.h | 3 + interface/src/avatar/Hand.cpp | 100 ++++++++++++----------- interface/src/avatar/Hand.h | 8 ++ interface/src/devices/SixenseManager.cpp | 63 ++++++++------ libraries/avatars/src/HandData.cpp | 9 +- libraries/avatars/src/HandData.h | 23 +++--- 8 files changed, 154 insertions(+), 86 deletions(-) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 378d86284a..f65e255495 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -289,7 +289,7 @@ inline void Audio::performIO(int16_t* inputLeft, int16_t* outputLeft, int16_t* o // add output (@speakers) data just written to the scope _scope->addSamples(1, outputLeft, BUFFER_LENGTH_SAMPLES_PER_CHANNEL); _scope->addSamples(2, outputRight, BUFFER_LENGTH_SAMPLES_PER_CHANNEL); - + gettimeofday(&_lastCallbackTime, NULL); } diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index 324f293110..5b151152ce 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -1567,6 +1567,38 @@ void VoxelSystem::falseColorizeInView() { setupNewVoxelsForDrawing(); } +class NodeAndPoint { +public: + VoxelNode* node; + glm::vec3 point; +}; + +// Find the smallest colored voxel enclosing a point (if there is one) +bool VoxelSystem::getVoxelEnclosingOperation(VoxelNode* node, void* extraData) { + NodeAndPoint* nodeAndPoint = (NodeAndPoint*) extraData; + AABox voxelBox = node->getAABox(); + if (voxelBox.contains(nodeAndPoint->point)) { + if (node->isColored() && node->isLeaf()) { + // we've reached a solid leaf containing the point, return the node. + nodeAndPoint->node = node; + return false; + } + } else { + // The point is not inside this voxel, so stop recursing. + return false; + } + return true; // keep looking +} + +VoxelNode* VoxelSystem::getVoxelEnclosing(const glm::vec3& point) { + NodeAndPoint nodeAndPoint; + nodeAndPoint.point = point; + nodeAndPoint.node = NULL; + _tree->recurseTreeWithOperation(getVoxelEnclosingOperation, (void*) &nodeAndPoint); + return nodeAndPoint.node; +} + + // helper classes and args for falseColorizeBySource class groupColor { public: diff --git a/interface/src/VoxelSystem.h b/interface/src/VoxelSystem.h index d9c672fdf3..91fe32d990 100644 --- a/interface/src/VoxelSystem.h +++ b/interface/src/VoxelSystem.h @@ -121,6 +121,8 @@ public: virtual void domainChanged(QString domain); bool treeIsBusy() const { return _treeIsBusy; } + + VoxelNode* getVoxelEnclosing(const glm::vec3& point); signals: void importSize(float x, float y, float z); @@ -200,6 +202,7 @@ private: static bool hideAllSubTreeOperation(VoxelNode* node, void* extraData); static bool showAllSubTreeOperation(VoxelNode* node, void* extraData); static bool showAllLocalVoxelsOperation(VoxelNode* node, void* extraData); + static bool getVoxelEnclosingOperation(VoxelNode* node, void* extraData); int updateNodeInArrays(VoxelNode* node, bool reuseIndex, bool forceDraw); int forceRemoveNodeFromArrays(VoxelNode* node); diff --git a/interface/src/avatar/Hand.cpp b/interface/src/avatar/Hand.cpp index d17c30d749..c95c3c901e 100755 --- a/interface/src/avatar/Hand.cpp +++ b/interface/src/avatar/Hand.cpp @@ -24,7 +24,10 @@ Hand::Hand(Avatar* owningAvatar) : _raveGloveInitialized(false), _owningAvatar(owningAvatar), _renderAlpha(1.0), - _ballColor(0.0, 0.0, 0.4) + _ballColor(0.0, 0.0, 0.4), + _collisionCenter(0,0,0), + _collisionAge(0), + _collisionDuration(0) { // initialize all finger particle emitters with an invalid id as default for (int f = 0; f< NUM_FINGERS; f ++ ) { @@ -51,6 +54,10 @@ void Hand::reset() { void Hand::simulate(float deltaTime, bool isMine) { + if (_collisionAge > 0.f) { + _collisionAge += deltaTime; + } + calculateGeometry(); if (_isRaveGloveActive) { @@ -67,8 +74,7 @@ void Hand::simulate(float deltaTime, bool isMine) { for (size_t i = 0; i < getNumPalms(); ++i) { PalmData& palm = getPalms()[i]; if (palm.isActive()) { - glm::vec3 palmPosition = palm.getPosition(); - FingerData& finger = palm.getFingers()[0]; + FingerData& finger = palm.getFingers()[0]; // Sixense has only one finger glm::vec3 fingerTipPosition = finger.getTipPosition(); if (palm.getControllerButtons() & BUTTON_1) { if (glm::length(fingerTipPosition - _lastFingerAddVoxel) > (FINGERTIP_VOXEL_SIZE / 2.f)) { @@ -88,55 +94,43 @@ void Hand::simulate(float deltaTime, bool isMine) { } } // Check if the finger is intersecting with a voxel in the client voxel tree - VoxelNode* fingerNode = Application::getInstance()->getVoxels()->getVoxelAt(fingerTipPosition.x / TREE_SCALE, - fingerTipPosition.y / TREE_SCALE, - fingerTipPosition.z / TREE_SCALE, - FINGERTIP_VOXEL_SIZE / TREE_SCALE); + VoxelNode* fingerNode = Application::getInstance()->getVoxels()->getVoxelEnclosing(glm::vec3(fingerTipPosition / (float)TREE_SCALE)); if (fingerNode) { - finger.setIsTouchingVoxel(true); - glm::vec3 corner = fingerNode->getCorner(); - glm::vec3 storedCorner = finger.getFingerVoxelPosition(); - printf("corner: %.3f, %.3f, %.3f ", corner.x, corner.y, corner.z); - printf("stored corner: %.3f, %.3f, %.3f\n", storedCorner.x, storedCorner.y, storedCorner.z); - if (finger.getIsTouchingVoxel()) printf("Touching! %f.3", randFloat()); - if (glm::length(fingerNode->getCorner() - finger.getFingerVoxelPosition()) > EPSILON) { - printf("diff = %.9f\n", glm::length(fingerNode->getCorner() - finger.getFingerVoxelPosition())); - finger.setFingerVoxelPosition(fingerNode->getCorner()); - finger.setFingerVoxelScale(fingerNode->getScale()); - printf("touching voxel scale, %0.4f\n", fingerNode->getScale() * TREE_SCALE); - printVector(glm::vec3(fingerNode->getCorner() * (float)TREE_SCALE)); + if (!palm.getIsCollidingWithVoxel()) { + // Collision has just started + palm.setIsCollidingWithVoxel(true); + handleVoxelCollision(&palm, fingerTipPosition, fingerNode, deltaTime); + } + } else { + if (palm.getIsCollidingWithVoxel()) { + // Collision has just ended + palm.setIsCollidingWithVoxel(false); } - /* - if ((currentFingerVoxel.x != _fingerVoxel.x) || - (currentFingerVoxel.y != _fingerVoxel.y) || - (currentFingerVoxel.z != _fingerVoxel.z) || - (currentFingerVoxel.s != _fingerVoxel.s) || - (currentFingerVoxel.red != _fingerVoxel.red) || - (currentFingerVoxel.green != _fingerVoxel.green) || - (currentFingerVoxel.blue != _fingerVoxel.blue)) { - memcpy(&_fingerVoxel, ¤tFingerVoxel, sizeof(VoxelDetail)); - _fingerIsOnVoxel = true; - Application::getInstance()->setHighlightVoxel(currentFingerVoxel); - Application::getInstance()->setIsHighlightVoxel(true); - printf("Moved onto a voxel %.2f, %.2f, %.2f s %.2f\n", - currentFingerVoxel.x * TREE_SCALE, - currentFingerVoxel.y * TREE_SCALE, - currentFingerVoxel.z * TREE_SCALE, - currentFingerVoxel.s * TREE_SCALE); - // If desired, make a sound - Application::getInstance()->getAudio()->startCollisionSound(1.0, 7040 * currentFingerVoxel.s * TREE_SCALE, 0.0, 0.999f, false); - } - */ - } else if (finger.getIsTouchingVoxel()) { - // Just moved off a voxel, change back it's color - printf("Moved out of voxel!\n"); - finger.setIsTouchingVoxel(false); - Application::getInstance()->setIsHighlightVoxel(false); } } } } +void Hand::handleVoxelCollision(PalmData* palm, const glm::vec3& fingerTipPosition, VoxelNode* voxel, float deltaTime) { + // + // Collision between finger and a voxel plays sound + // + float volume = glm::length(palm->getVelocity()); + float duration = volume; + _collisionCenter = fingerTipPosition; + _collisionAge = deltaTime; + _collisionDuration = duration; + int voxelBrightness = voxel->getColor()[0] + voxel->getColor()[1] + voxel->getColor()[2]; + float frequency = 100.f + (voxelBrightness * 2.f); // Hz + // Play a sound + Application::getInstance()->getAudio()->startCollisionSound(volume, + frequency, + 0.25, + 0.995f, + false); + +} + void Hand::calculateGeometry() { const glm::vec3 leapHandsOffsetFromFace(0.0, -0.2, -0.3); // place the hand in front of the face where we can see it @@ -233,6 +227,21 @@ void Hand::render() { } } + // If hand/voxel collision has happened, render a little expanding sphere + if (_collisionAge > 0.f) { + float opacity = glm::clamp(1.f - (_collisionAge / _collisionDuration), 0.f, 1.f); + glColor4f(1, 0, 0, 0.5 * opacity); + glPushMatrix(); + glTranslatef(_collisionCenter.x, _collisionCenter.y, _collisionCenter.z); + glutSolidSphere(_collisionAge * 0.25f, 20, 20); + glPopMatrix(); + if (_collisionAge > _collisionDuration) { + _collisionAge = 0.f; + } + } + + + // If hand controller buttons pressed, render stuff as needed if (getPalms().size() > 0) { for (size_t i = 0; i < getPalms().size(); ++i) { @@ -353,7 +362,6 @@ void Hand::renderLeapHands() { } else { glColor4f(handColor.r, handColor.g, handColor.b, alpha); } - glPushMatrix(); glTranslatef(_leapFingerTipBalls[i].position.x, _leapFingerTipBalls[i].position.y, _leapFingerTipBalls[i].position.z); glutSolidSphere(_leapFingerTipBalls[i].radius, 20.0f, 20.0f); diff --git a/interface/src/avatar/Hand.h b/interface/src/avatar/Hand.h index 5e8acdbaa6..d012efb9bd 100755 --- a/interface/src/avatar/Hand.h +++ b/interface/src/avatar/Hand.h @@ -84,6 +84,12 @@ private: std::vector _leapFingerRootBalls; glm::vec3 _lastFingerAddVoxel, _lastFingerDeleteVoxel; + bool _isCollidingWithVoxel; + VoxelDetail _collidingVoxel; + + glm::vec3 _collisionCenter; + float _collisionAge; + float _collisionDuration; // private methods void setLeapHands(const std::vector& handPositions, @@ -94,6 +100,8 @@ private: void renderLeapHands(); void renderLeapFingerTrails(); void calculateGeometry(); + + void handleVoxelCollision(PalmData* palm, const glm::vec3& fingerTipPosition, VoxelNode* voxel, float deltaTime); }; #endif diff --git a/interface/src/devices/SixenseManager.cpp b/interface/src/devices/SixenseManager.cpp index 8055e8112d..a55715550b 100644 --- a/interface/src/devices/SixenseManager.cpp +++ b/interface/src/devices/SixenseManager.cpp @@ -32,7 +32,6 @@ void SixenseManager::update(float deltaTime) { } MyAvatar* avatar = Application::getInstance()->getAvatar(); Hand& hand = avatar->getHand(); - hand.getPalms().clear(); int maxControllers = sixenseGetMaxControllers(); for (int i = 0; i < maxControllers; i++) { @@ -42,45 +41,63 @@ void SixenseManager::update(float deltaTime) { sixenseControllerData data; sixenseGetNewestData(i, &data); - // Set palm position and normal based on Hydra position/orientation - PalmData palm(&hand); - palm.setActive(true); - glm::vec3 position(data.pos[0], data.pos[1], data.pos[2]); + //printf("si: %i\n", data.controller_index); - // Compute current velocity from position change - palm.setVelocity((position - palm.getPosition()) / deltaTime); + // Set palm position and normal based on Hydra position/orientation + + // Either find a palm matching the sixense controller, or make a new one + PalmData* palm; + bool foundHand = false; + for (int j = 0; j < hand.getNumPalms(); j++) { + if (hand.getPalms()[j].getSixenseID() == data.controller_index) { + palm = &hand.getPalms()[j]; + foundHand = true; + } + } + if (!foundHand) { + PalmData newPalm(&hand); + hand.getPalms().push_back(newPalm); + palm = &hand.getPalms()[hand.getNumPalms() - 1]; + palm->setSixenseID(data.controller_index); + printf("Found new Sixense controller, ID %i\n", data.controller_index); + } + + palm->setActive(true); // Read controller buttons and joystick into the hand - palm.setControllerButtons(data.buttons); - palm.setTrigger(data.trigger); - palm.setJoystick(data.joystick_x, data.joystick_y); - + palm->setControllerButtons(data.buttons); + palm->setTrigger(data.trigger); + palm->setJoystick(data.joystick_x, data.joystick_y); + + glm::vec3 position(data.pos[0], data.pos[1], data.pos[2]); // Adjust for distance between acquisition 'orb' and the user's torso // (distance to the right of body center, distance below torso, distance behind torso) const glm::vec3 SPHERE_TO_TORSO(-250.f, -300.f, -300.f); position = SPHERE_TO_TORSO + position; - palm.setRawPosition(position); - glm::quat rotation(data.rot_quat[3], -data.rot_quat[0], data.rot_quat[1], -data.rot_quat[2]); - // Rotate about controller + // Compute current velocity from position change + palm->setVelocity((position - palm->getRawPosition()) / deltaTime / 1000.f); // meters/sec + palm->setRawPosition(position); + + // Rotation of Palm + glm::quat rotation(data.rot_quat[3], -data.rot_quat[0], data.rot_quat[1], -data.rot_quat[2]); rotation = glm::angleAxis(180.0f, 0.f, 1.f, 0.f) * rotation; const glm::vec3 PALM_VECTOR(0.0f, -1.0f, 0.0f); - palm.setRawNormal(rotation * PALM_VECTOR); + palm->setRawNormal(rotation * PALM_VECTOR); // initialize the "finger" based on the direction - FingerData finger(&palm, &hand); + FingerData finger(palm, &hand); finger.setActive(true); finger.setRawRootPosition(position); - const glm::vec3 FINGER_VECTOR(0.0f, 0.0f, 100.0f); + const float FINGER_LENGTH = 100.0f; // Millimeters + const glm::vec3 FINGER_VECTOR(0.0f, 0.0f, FINGER_LENGTH); finger.setRawTipPosition(position + rotation * FINGER_VECTOR); // three fingers indicates to the skeleton that we have enough data to determine direction - palm.getFingers().clear(); - palm.getFingers().push_back(finger); - palm.getFingers().push_back(finger); - palm.getFingers().push_back(finger); - - hand.getPalms().push_back(palm); + palm->getFingers().clear(); + palm->getFingers().push_back(finger); + palm->getFingers().push_back(finger); + palm->getFingers().push_back(finger); } #endif } diff --git a/libraries/avatars/src/HandData.cpp b/libraries/avatars/src/HandData.cpp index 06a30f9e38..a38e2dee6d 100644 --- a/libraries/avatars/src/HandData.cpp +++ b/libraries/avatars/src/HandData.cpp @@ -41,8 +41,10 @@ _velocity(0, 0, 0), _controllerButtons(0), _isActive(false), _leapID(LEAPID_INVALID), +_sixenseID(SIXENSEID_INVALID), _numFramesWithoutData(0), -_owningHandData(owningHandData) +_owningHandData(owningHandData), +_isCollidingWithVoxel(false) { for (int i = 0; i < NUM_FINGERS_PER_HAND; ++i) { _fingers.push_back(FingerData(this, owningHandData)); @@ -56,10 +58,7 @@ _isActive(false), _leapID(LEAPID_INVALID), _numFramesWithoutData(0), _owningPalmData(owningPalmData), -_owningHandData(owningHandData), -_isTouchingVoxel(false), -_fingerVoxelPosition(), -_fingerVoxelScale(0) +_owningHandData(owningHandData) { const int standardTrailLength = 10; setTrailLength(standardTrailLength); diff --git a/libraries/avatars/src/HandData.h b/libraries/avatars/src/HandData.h index c072d9afb2..8b43b64ef0 100755 --- a/libraries/avatars/src/HandData.h +++ b/libraries/avatars/src/HandData.h @@ -24,6 +24,7 @@ const int NUM_FINGERS_PER_HAND = 5; const int NUM_FINGERS = NUM_HANDS * NUM_FINGERS_PER_HAND; const int LEAPID_INVALID = -1; +const int SIXENSEID_INVALID = -1; enum RaveGloveEffectsMode { @@ -120,13 +121,6 @@ public: void resetFramesWithoutData() { _numFramesWithoutData = 0; } int getFramesWithoutData() const { return _numFramesWithoutData; } - void setIsTouchingVoxel(bool isTouchingVoxel) { _isTouchingVoxel = isTouchingVoxel; } - bool getIsTouchingVoxel() { return _isTouchingVoxel; } - void setFingerVoxelPosition(const glm::vec3& fingerVoxelPosition) { _fingerVoxelPosition = fingerVoxelPosition; } - const glm::vec3& getFingerVoxelPosition() const { return _fingerVoxelPosition; } - void setFingerVoxelScale(float fingerVoxelScale) { _fingerVoxelScale = fingerVoxelScale; } - float getFingerVoxelScale() { return _fingerVoxelScale; } - private: glm::vec3 _tipRawPosition; glm::vec3 _rootRawPosition; @@ -138,10 +132,6 @@ private: int _tipTrailCurrentValidLength; PalmData* _owningPalmData; HandData* _owningHandData; - - bool _isTouchingVoxel; - glm::vec3 _fingerVoxelPosition; - float _fingerVoxelScale; }; class PalmData { @@ -153,12 +143,16 @@ public: const glm::vec3& getRawNormal() const { return _rawNormal; } bool isActive() const { return _isActive; } int getLeapID() const { return _leapID; } + int getSixenseID() const { return _sixenseID; } + std::vector& getFingers() { return _fingers; } size_t getNumFingers() { return _fingers.size(); } void setActive(bool active) { _isActive = active; } void setLeapID(int id) { _leapID = id; } + void setSixenseID(int id) { _sixenseID = id; } + void setRawPosition(const glm::vec3& pos) { _rawPosition = pos; } void setRawNormal(const glm::vec3& normal) { _rawNormal = normal; } void setVelocity(const glm::vec3& velocity) { _velocity = velocity; } @@ -177,6 +171,9 @@ public: void setJoystick(float joystickX, float joystickY) { _joystickX = joystickX; _joystickY = joystickY; } float getJoystickX() { return _joystickX; } float getJoystickY() { return _joystickY; } + + bool getIsCollidingWithVoxel() { return _isCollidingWithVoxel; } + void setIsCollidingWithVoxel(bool isCollidingWithVoxel) { _isCollidingWithVoxel = isCollidingWithVoxel; } private: std::vector _fingers; @@ -189,8 +186,12 @@ private: bool _isActive; // This has current valid data int _leapID; // the Leap's serial id for this tracked object + int _sixenseID; // Sixense controller ID for this palm int _numFramesWithoutData; // after too many frames without data, this tracked object assumed lost. HandData* _owningHandData; + + bool _isCollidingWithVoxel; /// Whether the finger of this palm is inside a leaf voxel + }; #endif /* defined(__hifi__HandData__) */ From 423b2e8e0f58f860ee0802b817aa0c9351e56f34 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Tue, 3 Dec 2013 16:52:38 -0800 Subject: [PATCH 28/31] Highlight voxel being touched --- interface/src/Application.cpp | 13 ++++--------- interface/src/avatar/Hand.cpp | 13 +++++++++++++ 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 07996dd7db..2f9657efe5 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1994,17 +1994,13 @@ void Application::renderHighlightVoxel(VoxelDetail voxel) { glDisable(GL_LIGHTING); glPushMatrix(); glScalef(TREE_SCALE, TREE_SCALE, TREE_SCALE); - //printf("Render: %.6f,%.6f,%.6f %.8f\n", voxel.x, voxel.y, voxel.z, - // voxel.s); - const float EDGE_EXPAND = 1.01f; - //glColor3ub(voxel.red + 128, voxel.green + 128, voxel.blue + 128); - glColor3ub(255, 0, 0); - + const float EDGE_EXPAND = 1.02f; + glColor3ub(voxel.red + 128, voxel.green + 128, voxel.blue + 128); glTranslatef(voxel.x + voxel.s * 0.5f, voxel.y + voxel.s * 0.5f, voxel.z + voxel.s * 0.5f); - glLineWidth(4.0f); - glutWireCube(_mouseVoxel.s * EDGE_EXPAND); + glLineWidth(2.0f); + glutWireCube(voxel.s * EDGE_EXPAND); glPopMatrix(); } @@ -3033,7 +3029,6 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { } } - // restore default, white specular glMaterialfv(GL_FRONT, GL_SPECULAR, WHITE_SPECULAR_COLOR); diff --git a/interface/src/avatar/Hand.cpp b/interface/src/avatar/Hand.cpp index c95c3c901e..f703c505a4 100755 --- a/interface/src/avatar/Hand.cpp +++ b/interface/src/avatar/Hand.cpp @@ -100,11 +100,24 @@ void Hand::simulate(float deltaTime, bool isMine) { // Collision has just started palm.setIsCollidingWithVoxel(true); handleVoxelCollision(&palm, fingerTipPosition, fingerNode, deltaTime); + // Set highlight voxel + VoxelDetail voxel; + glm::vec3 pos = fingerNode->getCorner(); + voxel.x = pos.x; + voxel.y = pos.y; + voxel.z = pos.z; + voxel.s = fingerNode->getScale(); + voxel.red = fingerNode->getColor()[0]; + voxel.green = fingerNode->getColor()[1]; + voxel.blue = fingerNode->getColor()[2]; + Application::getInstance()->setHighlightVoxel(voxel); + Application::getInstance()->setIsHighlightVoxel(true); } } else { if (palm.getIsCollidingWithVoxel()) { // Collision has just ended palm.setIsCollidingWithVoxel(false); + Application::getInstance()->setIsHighlightVoxel(false); } } } From b04d48a7b813b573749a7b0b836482815420db1d Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Tue, 3 Dec 2013 17:19:00 -0800 Subject: [PATCH 29/31] Longer drum sticks --- interface/src/avatar/Hand.cpp | 2 +- interface/src/devices/SixenseManager.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/avatar/Hand.cpp b/interface/src/avatar/Hand.cpp index f703c505a4..658ca2002b 100755 --- a/interface/src/avatar/Hand.cpp +++ b/interface/src/avatar/Hand.cpp @@ -159,7 +159,7 @@ void Hand::calculateGeometry() { for (size_t f = 0; f < palm.getNumFingers(); ++f) { FingerData& finger = palm.getFingers()[f]; if (finger.isActive()) { - const float standardBallRadius = 0.005f; + const float standardBallRadius = 0.010f; _leapFingerTipBalls.resize(_leapFingerTipBalls.size() + 1); HandBall& ball = _leapFingerTipBalls.back(); ball.rotation = _baseOrientation; diff --git a/interface/src/devices/SixenseManager.cpp b/interface/src/devices/SixenseManager.cpp index a55715550b..1ee78126f8 100644 --- a/interface/src/devices/SixenseManager.cpp +++ b/interface/src/devices/SixenseManager.cpp @@ -89,7 +89,7 @@ void SixenseManager::update(float deltaTime) { FingerData finger(palm, &hand); finger.setActive(true); finger.setRawRootPosition(position); - const float FINGER_LENGTH = 100.0f; // Millimeters + const float FINGER_LENGTH = 300.0f; // Millimeters const glm::vec3 FINGER_VECTOR(0.0f, 0.0f, FINGER_LENGTH); finger.setRawTipPosition(position + rotation * FINGER_VECTOR); From 2dfbaf605e000d289ae2a0f090cc54d43aac2599 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Tue, 3 Dec 2013 23:01:13 -0800 Subject: [PATCH 30/31] Stars a bit dimmer, have horizon --- interface/src/starfield/Generator.cpp | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/interface/src/starfield/Generator.cpp b/interface/src/starfield/Generator.cpp index 63a11f8f11..d8d38a61a6 100644 --- a/interface/src/starfield/Generator.cpp +++ b/interface/src/starfield/Generator.cpp @@ -24,22 +24,24 @@ void Generator::computeStarPositions(InputVertices& destination, unsigned limit, vertices->clear(); vertices->reserve(limit); - const unsigned MILKY_WAY_WIDTH = 16.0; // width in degrees of one half of the Milky Way - const float MILKY_WAY_INCLINATION = 30.0f; // angle of Milky Way from horizontal in degrees - const float MILKY_WAY_RATIO = 0.6; + const unsigned MILKY_WAY_WIDTH = 12.0; // width in degrees of one half of the Milky Way + const float MILKY_WAY_INCLINATION = 0.0f; // angle of Milky Way from horizontal in degrees + const float MILKY_WAY_RATIO = 0.4; const unsigned NUM_DEGREES = 360; for(int star = 0; star < floor(limit * (1 - MILKY_WAY_RATIO)); ++star) { float azimuth, altitude; azimuth = (((float)rand() / (float) RAND_MAX) * NUM_DEGREES) - (NUM_DEGREES / 2); altitude = (acos((2.0f * ((float)rand() / (float)RAND_MAX)) - 1.0f) / PI_OVER_180) + 90; - vertices->push_back(InputVertex(azimuth, altitude, computeStarColor(STAR_COLORIZATION))); } for(int star = 0; star < ceil(limit * MILKY_WAY_RATIO); ++star) { float azimuth = ((float)rand() / (float) RAND_MAX) * NUM_DEGREES; - float altitude = asin((float)rand() / (float) RAND_MAX * 2 - 1) * MILKY_WAY_WIDTH; + float altitude = powf(randFloat()*0.5f, 2.f)/0.25f * MILKY_WAY_WIDTH; + if (randFloat() > 0.5f) { + altitude *= -1.f; + } // we need to rotate the Milky Way band to the correct orientation in the sky // convert from spherical coordinates to cartesian, rotate the point and then convert back. @@ -71,8 +73,15 @@ void Generator::computeStarPositions(InputVertices& destination, unsigned limit, // 0 = completely black & white // 1 = very colorful unsigned Generator::computeStarColor(float colorization) { - unsigned char red = rand() % 256; - unsigned char green = round((red * (1 - colorization)) + ((rand() % 256) * colorization)); - unsigned char blue = round((red * (1 - colorization)) + ((rand() % 256) * colorization)); - return red | green << 8 | blue << 16; + unsigned char red, green, blue; + if (randFloat() < 0.3f) { + // A few stars are colorful + red = 2 + (rand() % 254); + green = 2 + round((red * (1 - colorization)) + ((rand() % 254) * colorization)); + blue = 2 + round((red * (1 - colorization)) + ((rand() % 254) * colorization)); + } else { + // Most stars are dimmer and white + red = green = blue = 2 + (rand() % 128); + } + return red | (green << 8) | (blue << 16); } \ No newline at end of file From 457c3cc8d9c0b40e81680a111aee2cfd544db51a Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 4 Dec 2013 11:19:16 -0800 Subject: [PATCH 31/31] remove unneeded VoxelTree in VoxelScriptingInterface --- assignment-client/src/voxels/VoxelScriptingInterface.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/assignment-client/src/voxels/VoxelScriptingInterface.h b/assignment-client/src/voxels/VoxelScriptingInterface.h index fc1426ebbc..473cf3035c 100644 --- a/assignment-client/src/voxels/VoxelScriptingInterface.h +++ b/assignment-client/src/voxels/VoxelScriptingInterface.h @@ -13,7 +13,6 @@ #include #include -#include /// handles scripting of voxel commands from JS passed to assigned clients class VoxelScriptingInterface : public QObject { @@ -23,7 +22,6 @@ public: VoxelEditPacketSender* getVoxelPacketSender() { return &_voxelPacketSender; } JurisdictionListener* getJurisdictionListener() { return &_jurisdictionListener; } - VoxelTree* getVoxelTree() { return &_voxelTree; } public slots: /// queues the creation of a voxel which will be sent by calling process on the PacketSender /// \param x the x-coordinate of the voxel (in VS space) @@ -107,7 +105,6 @@ private: /// attached VoxelEditPacketSender that handles queuing and sending of packets to VS VoxelEditPacketSender _voxelPacketSender; JurisdictionListener _jurisdictionListener; - VoxelTree _voxelTree; void queueVoxelAdd(PACKET_TYPE addPacketType, VoxelDetail& addVoxelDetails); };