Merge branch 'master' of git://github.com/worklist/hifi

This commit is contained in:
Atlante45 2013-07-11 14:50:18 -07:00
commit 1b67f8fb24
34 changed files with 527 additions and 352 deletions

View file

@ -48,11 +48,11 @@ bool wantLocalDomain = false;
unsigned long packetsSent = 0; unsigned long packetsSent = 0;
unsigned long bytesSent = 0; unsigned long bytesSent = 0;
static void sendVoxelEditMessage(PACKET_HEADER header, VoxelDetail& detail) { static void sendVoxelEditMessage(PACKET_TYPE type, VoxelDetail& detail) {
unsigned char* bufferOut; unsigned char* bufferOut;
int sizeOut; int sizeOut;
if (createVoxelEditMessage(header, 0, 1, &detail, bufferOut, sizeOut)){ if (createVoxelEditMessage(type, 0, 1, &detail, bufferOut, sizeOut)){
::packetsSent++; ::packetsSent++;
::bytesSent += sizeOut; ::bytesSent += sizeOut;
@ -161,7 +161,7 @@ static void renderMovingBug() {
} }
// send the "erase message" first... // send the "erase message" first...
PACKET_HEADER message = PACKET_HEADER_ERASE_VOXEL; PACKET_TYPE message = PACKET_TYPE_ERASE_VOXEL;
if (createVoxelEditMessage(message, 0, VOXELS_PER_BUG, (VoxelDetail*)&details, bufferOut, sizeOut)){ if (createVoxelEditMessage(message, 0, VOXELS_PER_BUG, (VoxelDetail*)&details, bufferOut, sizeOut)){
::packetsSent++; ::packetsSent++;
@ -231,7 +231,7 @@ static void renderMovingBug() {
} }
// send the "create message" ... // send the "create message" ...
message = PACKET_HEADER_SET_VOXEL_DESTRUCTIVE; message = PACKET_TYPE_SET_VOXEL_DESTRUCTIVE;
if (createVoxelEditMessage(message, 0, VOXELS_PER_BUG, (VoxelDetail*)&details, bufferOut, sizeOut)){ if (createVoxelEditMessage(message, 0, VOXELS_PER_BUG, (VoxelDetail*)&details, bufferOut, sizeOut)){
::packetsSent++; ::packetsSent++;
@ -276,7 +276,7 @@ static void sendVoxelBlinkMessage() {
detail.green = 0 * ::intensity; detail.green = 0 * ::intensity;
detail.blue = 0 * ::intensity; detail.blue = 0 * ::intensity;
PACKET_HEADER message = PACKET_HEADER_SET_VOXEL_DESTRUCTIVE; PACKET_TYPE message = PACKET_TYPE_SET_VOXEL_DESTRUCTIVE;
sendVoxelEditMessage(message, detail); sendVoxelEditMessage(message, detail);
} }
@ -293,7 +293,7 @@ unsigned char onColor[3] = { 0, 255, 255 };
const float STRING_OF_LIGHTS_SIZE = 0.125f / TREE_SCALE; // approximately 1/8th meter const float STRING_OF_LIGHTS_SIZE = 0.125f / TREE_SCALE; // approximately 1/8th meter
static void sendBlinkingStringOfLights() { static void sendBlinkingStringOfLights() {
PACKET_HEADER message = PACKET_HEADER_SET_VOXEL_DESTRUCTIVE; // we're a bully! PACKET_TYPE message = PACKET_TYPE_SET_VOXEL_DESTRUCTIVE; // we're a bully!
float lightScale = STRING_OF_LIGHTS_SIZE; float lightScale = STRING_OF_LIGHTS_SIZE;
static VoxelDetail details[LIGHTS_PER_SEGMENT]; static VoxelDetail details[LIGHTS_PER_SEGMENT];
unsigned char* bufferOut; unsigned char* bufferOut;
@ -423,7 +423,7 @@ const int PACKETS_PER_DANCE_FLOOR = DANCE_FLOOR_VOXELS_PER_PACKET / (DANCE_FLOOR
int danceFloorColors[DANCE_FLOOR_WIDTH][DANCE_FLOOR_LENGTH]; int danceFloorColors[DANCE_FLOOR_WIDTH][DANCE_FLOOR_LENGTH];
void sendDanceFloor() { void sendDanceFloor() {
PACKET_HEADER message = PACKET_HEADER_SET_VOXEL_DESTRUCTIVE; // we're a bully! PACKET_TYPE message = PACKET_TYPE_SET_VOXEL_DESTRUCTIVE; // we're a bully!
float lightScale = DANCE_FLOOR_LIGHT_SIZE; float lightScale = DANCE_FLOOR_LIGHT_SIZE;
static VoxelDetail details[DANCE_FLOOR_VOXELS_PER_PACKET]; static VoxelDetail details[DANCE_FLOOR_VOXELS_PER_PACKET];
unsigned char* bufferOut; unsigned char* bufferOut;
@ -550,7 +550,7 @@ bool billboardMessage[BILLBOARD_HEIGHT][BILLBOARD_WIDTH] = {
}; };
static void sendBillboard() { static void sendBillboard() {
PACKET_HEADER message = PACKET_HEADER_SET_VOXEL_DESTRUCTIVE; // we're a bully! PACKET_TYPE message = PACKET_TYPE_SET_VOXEL_DESTRUCTIVE; // we're a bully!
float lightScale = BILLBOARD_LIGHT_SIZE; float lightScale = BILLBOARD_LIGHT_SIZE;
static VoxelDetail details[VOXELS_PER_PACKET]; static VoxelDetail details[VOXELS_PER_PACKET];
unsigned char* bufferOut; unsigned char* bufferOut;
@ -726,7 +726,8 @@ int main(int argc, const char * argv[])
} }
// Nodes sending messages to us... // Nodes sending messages to us...
if (nodeList->getNodeSocket()->receive(&nodePublicAddress, packetData, &receivedBytes)) { if (nodeList->getNodeSocket()->receive(&nodePublicAddress, packetData, &receivedBytes) &&
packetVersionMatch(packetData)) {
NodeList::getInstance()->processNodeData(&nodePublicAddress, packetData, receivedBytes); NodeList::getInstance()->processNodeData(&nodePublicAddress, packetData, receivedBytes);
} }
} }

View file

@ -24,6 +24,6 @@ AvatarAudioRingBuffer::~AvatarAudioRingBuffer() {
} }
int AvatarAudioRingBuffer::parseData(unsigned char* sourceBuffer, int numBytes) { int AvatarAudioRingBuffer::parseData(unsigned char* sourceBuffer, int numBytes) {
_shouldLoopbackForNode = (sourceBuffer[0] == PACKET_HEADER_MICROPHONE_AUDIO_WITH_ECHO); _shouldLoopbackForNode = (sourceBuffer[0] == PACKET_TYPE_MICROPHONE_AUDIO_WITH_ECHO);
return PositionalAudioRingBuffer::parseData(sourceBuffer, numBytes); return PositionalAudioRingBuffer::parseData(sourceBuffer, numBytes);
} }

View file

@ -21,7 +21,7 @@ InjectedAudioRingBuffer::InjectedAudioRingBuffer() :
} }
int InjectedAudioRingBuffer::parseData(unsigned char* sourceBuffer, int numBytes) { int InjectedAudioRingBuffer::parseData(unsigned char* sourceBuffer, int numBytes) {
unsigned char* currentBuffer = sourceBuffer + sizeof(PACKET_HEADER_INJECT_AUDIO); unsigned char* currentBuffer = sourceBuffer + numBytesForPacketHeader(sourceBuffer);
// pull stream identifier from the packet // pull stream identifier from the packet
memcpy(&_streamIdentifier, currentBuffer, sizeof(_streamIdentifier)); memcpy(&_streamIdentifier, currentBuffer, sizeof(_streamIdentifier));

View file

@ -22,7 +22,7 @@ PositionalAudioRingBuffer::PositionalAudioRingBuffer() :
} }
int PositionalAudioRingBuffer::parseData(unsigned char* sourceBuffer, int numBytes) { int PositionalAudioRingBuffer::parseData(unsigned char* sourceBuffer, int numBytes) {
unsigned char* currentBuffer = sourceBuffer + sizeof(PACKET_HEADER); unsigned char* currentBuffer = sourceBuffer + numBytesForPacketHeader(sourceBuffer);
currentBuffer += parsePositionalData(currentBuffer, numBytes - (currentBuffer - sourceBuffer)); currentBuffer += parsePositionalData(currentBuffer, numBytes - (currentBuffer - sourceBuffer));
currentBuffer += parseAudioSamples(currentBuffer, numBytes - (currentBuffer - sourceBuffer)); currentBuffer += parseAudioSamples(currentBuffer, numBytes - (currentBuffer - sourceBuffer));

View file

@ -97,8 +97,9 @@ int main(int argc, const char* argv[]) {
int nextFrame = 0; int nextFrame = 0;
timeval startTime; timeval startTime;
unsigned char clientPacket[BUFFER_LENGTH_BYTES_STEREO + sizeof(PACKET_HEADER_MIXED_AUDIO)]; int numBytesPacketHeader = numBytesForPacketHeader((unsigned char*) &PACKET_TYPE_MIXED_AUDIO);
clientPacket[0] = PACKET_HEADER_MIXED_AUDIO; unsigned char clientPacket[BUFFER_LENGTH_BYTES_STEREO + numBytesPacketHeader];
populateTypeAndVersion(clientPacket, PACKET_TYPE_MIXED_AUDIO);
int16_t clientSamples[BUFFER_LENGTH_SAMPLES_PER_CHANNEL * 2] = {}; int16_t clientSamples[BUFFER_LENGTH_SAMPLES_PER_CHANNEL * 2] = {};
@ -326,7 +327,7 @@ int main(int argc, const char* argv[]) {
} }
} }
memcpy(clientPacket + sizeof(PACKET_HEADER_MIXED_AUDIO), clientSamples, sizeof(clientSamples)); memcpy(clientPacket + numBytesPacketHeader, clientSamples, sizeof(clientSamples));
nodeList->getNodeSocket()->send(node->getPublicSocket(), clientPacket, sizeof(clientPacket)); nodeList->getNodeSocket()->send(node->getPublicSocket(), clientPacket, sizeof(clientPacket));
} }
} }
@ -346,13 +347,14 @@ int main(int argc, const char* argv[]) {
} }
// pull any new audio data from nodes off of the network stack // pull any new audio data from nodes off of the network stack
while (nodeList->getNodeSocket()->receive(nodeAddress, packetData, &receivedBytes)) { while (nodeList->getNodeSocket()->receive(nodeAddress, packetData, &receivedBytes) &&
if (packetData[0] == PACKET_HEADER_MICROPHONE_AUDIO_NO_ECHO || packetVersionMatch(packetData)) {
packetData[0] == PACKET_HEADER_MICROPHONE_AUDIO_WITH_ECHO) { if (packetData[0] == PACKET_TYPE_MICROPHONE_AUDIO_NO_ECHO ||
packetData[0] == PACKET_TYPE_MICROPHONE_AUDIO_WITH_ECHO) {
Node* avatarNode = nodeList->addOrUpdateNode(nodeAddress, Node* avatarNode = nodeList->addOrUpdateNode(nodeAddress,
nodeAddress, nodeAddress,
NODE_TYPE_AGENT, NODE_TYPE_AGENT,
nodeList->getLastNodeID()); nodeList->getLastNodeID());
if (avatarNode->getNodeID() == nodeList->getLastNodeID()) { if (avatarNode->getNodeID() == nodeList->getLastNodeID()) {
nodeList->increaseNodeID(); nodeList->increaseNodeID();
@ -364,7 +366,7 @@ int main(int argc, const char* argv[]) {
// kill off this node - temporary solution to mixer crash on mac sleep // kill off this node - temporary solution to mixer crash on mac sleep
avatarNode->setAlive(false); avatarNode->setAlive(false);
} }
} else if (packetData[0] == PACKET_HEADER_INJECT_AUDIO) { } else if (packetData[0] == PACKET_TYPE_INJECT_AUDIO) {
Node* matchingInjector = NULL; Node* matchingInjector = NULL;
for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
@ -383,16 +385,16 @@ int main(int argc, const char* argv[]) {
if (!matchingInjector) { if (!matchingInjector) {
matchingInjector = nodeList->addOrUpdateNode(NULL, matchingInjector = nodeList->addOrUpdateNode(NULL,
NULL, NULL,
NODE_TYPE_AUDIO_INJECTOR, NODE_TYPE_AUDIO_INJECTOR,
nodeList->getLastNodeID()); nodeList->getLastNodeID());
nodeList->increaseNodeID(); nodeList->increaseNodeID();
} }
// give the new audio data to the matching injector node // give the new audio data to the matching injector node
nodeList->updateNodeWithData(matchingInjector, packetData, receivedBytes); nodeList->updateNodeWithData(matchingInjector, packetData, receivedBytes);
} else if (packetData[0] == PACKET_HEADER_PING) { } else if (packetData[0] == PACKET_TYPE_PING) {
// If the packet is a ping, let processNodeData handle it. // If the packet is a ping, let processNodeData handle it.
nodeList->processNodeData(nodeAddress, packetData, receivedBytes); nodeList->processNodeData(nodeAddress, packetData, receivedBytes);

View file

@ -73,7 +73,7 @@ int main(int argc, const char* argv[]) {
ssize_t receivedBytes = 0; ssize_t receivedBytes = 0;
unsigned char *broadcastPacket = new unsigned char[MAX_PACKET_SIZE]; unsigned char *broadcastPacket = new unsigned char[MAX_PACKET_SIZE];
*broadcastPacket = PACKET_HEADER_BULK_AVATAR_DATA; int numHeaderBytes = populateTypeAndVersion(broadcastPacket, PACKET_TYPE_BULK_AVATAR_DATA);
unsigned char* currentBufferPosition = NULL; unsigned char* currentBufferPosition = NULL;
@ -92,9 +92,10 @@ int main(int argc, const char* argv[]) {
NodeList::getInstance()->sendDomainServerCheckIn(); NodeList::getInstance()->sendDomainServerCheckIn();
} }
if (nodeList->getNodeSocket()->receive(nodeAddress, packetData, &receivedBytes)) { if (nodeList->getNodeSocket()->receive(nodeAddress, packetData, &receivedBytes) &&
packetVersionMatch(packetData)) {
switch (packetData[0]) { switch (packetData[0]) {
case PACKET_HEADER_HEAD_DATA: case PACKET_TYPE_HEAD_DATA:
// grab the node ID from the packet // grab the node ID from the packet
unpackNodeId(packetData + 1, &nodeID); unpackNodeId(packetData + 1, &nodeID);
@ -103,8 +104,8 @@ int main(int argc, const char* argv[]) {
// parse positional data from an node // parse positional data from an node
nodeList->updateNodeWithData(avatarNode, packetData, receivedBytes); nodeList->updateNodeWithData(avatarNode, packetData, receivedBytes);
case PACKET_HEADER_INJECT_AUDIO: case PACKET_TYPE_INJECT_AUDIO:
currentBufferPosition = broadcastPacket + 1; currentBufferPosition = broadcastPacket + numHeaderBytes;
// send back a packet with other active node data to this node // send back a packet with other active node data to this node
for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
@ -116,9 +117,9 @@ int main(int argc, const char* argv[]) {
nodeList->getNodeSocket()->send(nodeAddress, broadcastPacket, currentBufferPosition - broadcastPacket); nodeList->getNodeSocket()->send(nodeAddress, broadcastPacket, currentBufferPosition - broadcastPacket);
break; break;
case PACKET_HEADER_AVATAR_VOXEL_URL: case PACKET_TYPE_AVATAR_VOXEL_URL:
// grab the node ID from the packet // grab the node ID from the packet
unpackNodeId(packetData + 1, &nodeID); unpackNodeId(packetData + numBytesForPacketHeader(packetData), &nodeID);
// let everyone else know about the update // let everyone else know about the update
for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
@ -127,7 +128,7 @@ int main(int argc, const char* argv[]) {
} }
} }
break; break;
case PACKET_HEADER_DOMAIN: case PACKET_TYPE_DOMAIN:
// ignore the DS packet, for now nodes are added only when they communicate directly with us // ignore the DS packet, for now nodes are added only when they communicate directly with us
break; break;
default: default:

View file

@ -70,7 +70,7 @@ int main(int argc, const char * argv[])
char nodeType = '\0'; char nodeType = '\0';
unsigned char broadcastPacket[MAX_PACKET_SIZE]; unsigned char broadcastPacket[MAX_PACKET_SIZE];
broadcastPacket[0] = PACKET_HEADER_DOMAIN; int numHeaderBytes = populateTypeAndVersion(broadcastPacket, PACKET_TYPE_DOMAIN);
unsigned char* currentBufferPos; unsigned char* currentBufferPos;
unsigned char* startPointer; unsigned char* startPointer;
@ -86,11 +86,15 @@ int main(int argc, const char * argv[])
while (true) { while (true) {
if (nodeList->getNodeSocket()->receive((sockaddr *)&nodePublicAddress, packetData, &receivedBytes) && if (nodeList->getNodeSocket()->receive((sockaddr *)&nodePublicAddress, packetData, &receivedBytes) &&
(packetData[0] == PACKET_HEADER_DOMAIN_REPORT_FOR_DUTY || packetData[0] == PACKET_HEADER_DOMAIN_LIST_REQUEST)) { (packetData[0] == PACKET_TYPE_DOMAIN_REPORT_FOR_DUTY || packetData[0] == PACKET_TYPE_DOMAIN_LIST_REQUEST) &&
packetVersionMatch(packetData)) {
// this is an RFD or domain list request packet, and there is a version match
std::map<char, Node *> newestSoloNodes; std::map<char, Node *> newestSoloNodes;
nodeType = packetData[1]; int numBytesSenderHeader = numBytesForPacketHeader(packetData);
int numBytesSocket = unpackSocket(packetData + sizeof(PACKET_HEADER) + sizeof(NODE_TYPE),
nodeType = *(packetData + numBytesSenderHeader);
int numBytesSocket = unpackSocket(packetData + numBytesSenderHeader + sizeof(NODE_TYPE),
(sockaddr*) &nodeLocalAddress); (sockaddr*) &nodeLocalAddress);
sockaddr* destinationSocket = (sockaddr*) &nodePublicAddress; sockaddr* destinationSocket = (sockaddr*) &nodePublicAddress;
@ -108,18 +112,18 @@ int main(int argc, const char * argv[])
} }
Node* newNode = nodeList->addOrUpdateNode((sockaddr*) &nodePublicAddress, Node* newNode = nodeList->addOrUpdateNode((sockaddr*) &nodePublicAddress,
(sockaddr*) &nodeLocalAddress, (sockaddr*) &nodeLocalAddress,
nodeType, nodeType,
nodeList->getLastNodeID()); nodeList->getLastNodeID());
if (newNode->getNodeID() == nodeList->getLastNodeID()) { if (newNode->getNodeID() == nodeList->getLastNodeID()) {
nodeList->increaseNodeID(); nodeList->increaseNodeID();
} }
currentBufferPos = broadcastPacket + sizeof(PACKET_HEADER); currentBufferPos = broadcastPacket + numHeaderBytes;
startPointer = currentBufferPos; startPointer = currentBufferPos;
unsigned char* nodeTypesOfInterest = packetData + sizeof(PACKET_HEADER) + sizeof(NODE_TYPE) unsigned char* nodeTypesOfInterest = packetData + numBytesSenderHeader + sizeof(NODE_TYPE)
+ numBytesSocket + sizeof(unsigned char); + numBytesSocket + sizeof(unsigned char);
int numInterestTypes = *(nodeTypesOfInterest - 1); int numInterestTypes = *(nodeTypesOfInterest - 1);
@ -162,7 +166,7 @@ int main(int argc, const char * argv[])
uint64_t timeNow = usecTimestampNow(); uint64_t timeNow = usecTimestampNow();
newNode->setLastHeardMicrostamp(timeNow); newNode->setLastHeardMicrostamp(timeNow);
if (packetData[0] == PACKET_HEADER_DOMAIN_REPORT_FOR_DUTY if (packetData[0] == PACKET_TYPE_DOMAIN_REPORT_FOR_DUTY
&& memchr(SOLO_NODE_TYPES, nodeType, sizeof(SOLO_NODE_TYPES))) { && memchr(SOLO_NODE_TYPES, nodeType, sizeof(SOLO_NODE_TYPES))) {
newNode->setWakeMicrostamp(timeNow); newNode->setWakeMicrostamp(timeNow);
} }
@ -172,8 +176,8 @@ int main(int argc, const char * argv[])
// send the constructed list back to this node // send the constructed list back to this node
nodeList->getNodeSocket()->send(destinationSocket, nodeList->getNodeSocket()->send(destinationSocket,
broadcastPacket, broadcastPacket,
(currentBufferPos - startPointer) + 1); (currentBufferPos - startPointer) + numHeaderBytes);
} }
if (Logstash::shouldSendStats()) { if (Logstash::shouldSendStats()) {

View file

@ -49,9 +49,10 @@ void *receiveNodeData(void *args) {
NodeList* nodeList = NodeList::getInstance(); NodeList* nodeList = NodeList::getInstance();
while (!::stopReceiveNodeDataThread) { while (!::stopReceiveNodeDataThread) {
if (nodeList->getNodeSocket()->receive(&senderAddress, incomingPacket, &bytesReceived)) { if (nodeList->getNodeSocket()->receive(&senderAddress, incomingPacket, &bytesReceived) &&
packetVersionMatch(incomingPacket)) {
switch (incomingPacket[0]) { switch (incomingPacket[0]) {
case PACKET_HEADER_BULK_AVATAR_DATA: case PACKET_TYPE_BULK_AVATAR_DATA:
// this is the positional data for other nodes // this is the positional data for other nodes
// pass that off to the nodeList processBulkNodeData method // pass that off to the nodeList processBulkNodeData method
nodeList->processBulkNodeData(&senderAddress, incomingPacket, bytesReceived); nodeList->processBulkNodeData(&senderAddress, incomingPacket, bytesReceived);
@ -85,9 +86,6 @@ int main(int argc, const char* argv[]) {
// start the node list thread that will kill off nodes when they stop talking // start the node list thread that will kill off nodes when they stop talking
nodeList->startSilentNodeRemovalThread(); nodeList->startSilentNodeRemovalThread();
// start the ping thread that hole punches to create an active connection to other nodes
nodeList->startPingUnknownNodesThread();
pthread_t receiveNodeDataThread; pthread_t receiveNodeDataThread;
pthread_create(&receiveNodeDataThread, NULL, receiveNodeData, NULL); pthread_create(&receiveNodeDataThread, NULL, receiveNodeData, NULL);
@ -125,7 +123,7 @@ int main(int argc, const char* argv[]) {
nodeList->linkedDataCreateCallback = createAvatarDataForNode; nodeList->linkedDataCreateCallback = createAvatarDataForNode;
unsigned char broadcastPacket[MAX_PACKET_SIZE]; unsigned char broadcastPacket[MAX_PACKET_SIZE];
broadcastPacket[0] = PACKET_HEADER_HEAD_DATA; int numHeaderBytes = populateTypeAndVersion(broadcastPacket, PACKET_TYPE_HEAD_DATA);
timeval thisSend; timeval thisSend;
int numMicrosecondsSleep = 0; int numMicrosecondsSleep = 0;
@ -153,7 +151,7 @@ int main(int argc, const char* argv[]) {
// make sure we actually have an avatar mixer with an active socket // make sure we actually have an avatar mixer with an active socket
if (nodeList->getOwnerID() != UNKNOWN_NODE_ID && avatarMixer && avatarMixer->getActiveSocket() != NULL) { if (nodeList->getOwnerID() != UNKNOWN_NODE_ID && avatarMixer && avatarMixer->getActiveSocket() != NULL) {
unsigned char* packetPosition = broadcastPacket + sizeof(PACKET_HEADER); unsigned char* packetPosition = broadcastPacket + numHeaderBytes;
packetPosition += packNodeId(packetPosition, nodeList->getOwnerID()); packetPosition += packNodeId(packetPosition, nodeList->getOwnerID());
// use the getBroadcastData method in the AvatarData class to populate the broadcastPacket buffer // use the getBroadcastData method in the AvatarData class to populate the broadcastPacket buffer
@ -210,6 +208,5 @@ int main(int argc, const char* argv[]) {
pthread_join(receiveNodeDataThread, NULL); pthread_join(receiveNodeDataThread, NULL);
// stop the node list's threads // stop the node list's threads
nodeList->stopPingUnknownNodesThread();
nodeList->stopSilentNodeRemovalThread(); nodeList->stopSilentNodeRemovalThread();
} }

View file

@ -144,7 +144,8 @@ int main(int argc, char* argv[]) {
nodeList->linkedDataCreateCallback = createAvatarDataForNode; nodeList->linkedDataCreateCallback = createAvatarDataForNode;
timeval lastSend = {}; timeval lastSend = {};
unsigned char broadcastPacket = PACKET_HEADER_INJECT_AUDIO; int numBytesPacketHeader = numBytesForPacketHeader((unsigned char*) &PACKET_TYPE_INJECT_AUDIO);
unsigned char* broadcastPacket = new unsigned char[numBytesPacketHeader];
timeval lastDomainServerCheckIn = {}; timeval lastDomainServerCheckIn = {};
@ -168,10 +169,10 @@ int main(int argc, char* argv[]) {
NodeList::getInstance()->sendDomainServerCheckIn(); NodeList::getInstance()->sendDomainServerCheckIn();
} }
while (nodeList->getNodeSocket()->receive(&senderAddress, incomingPacket, &bytesReceived)) { while (nodeList->getNodeSocket()->receive(&senderAddress, incomingPacket, &bytesReceived) &&
packetVersionMatch(incomingPacket)) {
switch (incomingPacket[0]) { switch (incomingPacket[0]) {
case PACKET_HEADER_BULK_AVATAR_DATA: case PACKET_TYPE_BULK_AVATAR_DATA: // this is the positional data for other nodes
// this is the positional data for other nodes
// pass that off to the nodeList processBulkNodeData method // pass that off to the nodeList processBulkNodeData method
nodeList->processBulkNodeData(&senderAddress, incomingPacket, bytesReceived); nodeList->processBulkNodeData(&senderAddress, incomingPacket, bytesReceived);
break; break;
@ -211,8 +212,8 @@ int main(int argc, char* argv[]) {
// use the UDPSocket instance attached to our node list to ask avatar mixer for a list of avatars // use the UDPSocket instance attached to our node list to ask avatar mixer for a list of avatars
nodeList->getNodeSocket()->send(avatarMixer->getActiveSocket(), nodeList->getNodeSocket()->send(avatarMixer->getActiveSocket(),
&broadcastPacket, broadcastPacket,
sizeof(broadcastPacket)); numBytesPacketHeader);
} }
} else { } else {
if (!injector.isInjectingAudio() && (::shouldLoopAudio || !::hasInjectedAudioOnce)) { if (!injector.isInjectingAudio() && (::shouldLoopAudio || !::hasInjectedAudioOnce)) {

View file

@ -251,7 +251,6 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
// start the nodeList threads // start the nodeList threads
NodeList::getInstance()->startSilentNodeRemovalThread(); NodeList::getInstance()->startSilentNodeRemovalThread();
NodeList::getInstance()->startPingUnknownNodesThread();
_window->setCentralWidget(_glWidget); _window->setCentralWidget(_glWidget);
@ -905,14 +904,15 @@ void Application::wheelEvent(QWheelEvent* event) {
void Application::sendPingPackets() { void Application::sendPingPackets() {
char nodeTypesOfInterest[] = {NODE_TYPE_VOXEL_SERVER, NODE_TYPE_AUDIO_MIXER, NODE_TYPE_AVATAR_MIXER}; const char nodesToPing[] = {NODE_TYPE_VOXEL_SERVER, NODE_TYPE_AUDIO_MIXER, NODE_TYPE_AVATAR_MIXER};
uint64_t currentTime = usecTimestampNow();
unsigned char pingPacket[1 + sizeof(currentTime)];
pingPacket[0] = PACKET_HEADER_PING;
memcpy(&pingPacket[1], &currentTime, sizeof(currentTime)); uint64_t currentTime = usecTimestampNow();
getInstance()->controlledBroadcastToNodes(pingPacket, 1 + sizeof(currentTime), unsigned char pingPacket[numBytesForPacketHeader((unsigned char*) &PACKET_TYPE_PING) + sizeof(currentTime)];
nodeTypesOfInterest, sizeof(nodeTypesOfInterest)); int numHeaderBytes = populateTypeAndVersion(pingPacket, PACKET_TYPE_PING);
memcpy(pingPacket + numHeaderBytes, &currentTime, sizeof(currentTime));
getInstance()->controlledBroadcastToNodes(pingPacket, sizeof(pingPacket),
nodesToPing, sizeof(nodesToPing));
} }
// Every second, check the frame rates and other stuff // Every second, check the frame rates and other stuff
@ -1020,7 +1020,11 @@ void Application::sendAvatarVoxelURLMessage(const QUrl& url) {
return; // we don't yet know who we are return; // we don't yet know who we are
} }
QByteArray message; QByteArray message;
message.append(PACKET_HEADER_AVATAR_VOXEL_URL);
char packetHeader[MAX_PACKET_HEADER_BYTES];
int numBytesPacketHeader = populateTypeAndVersion((unsigned char*) packetHeader, PACKET_TYPE_AVATAR_VOXEL_URL);
message.append(packetHeader, numBytesPacketHeader);
message.append((const char*)&ownerID, sizeof(ownerID)); message.append((const char*)&ownerID, sizeof(ownerID));
message.append(url.toEncoded()); message.append(url.toEncoded());
@ -1029,8 +1033,9 @@ void Application::sendAvatarVoxelURLMessage(const QUrl& url) {
void Application::processAvatarVoxelURLMessage(unsigned char *packetData, size_t dataBytes) { void Application::processAvatarVoxelURLMessage(unsigned char *packetData, size_t dataBytes) {
// skip the header // skip the header
packetData++; int numBytesPacketHeader = numBytesForPacketHeader(packetData);
dataBytes--; packetData += numBytesPacketHeader;
dataBytes -= numBytesPacketHeader;
// read the node id // read the node id
uint16_t nodeID = *(uint16_t*)packetData; uint16_t nodeID = *(uint16_t*)packetData;
@ -1231,12 +1236,16 @@ void Application::doTreeStats() {
_voxels.collectStatsForTreesAndVBOs(); _voxels.collectStatsForTreesAndVBOs();
} }
void Application::setWantsLowResMoving(bool wantsLowResMoving) {
_myAvatar.setWantLowResMoving(wantsLowResMoving);
}
void Application::setWantsMonochrome(bool wantsMonochrome) { void Application::setWantsMonochrome(bool wantsMonochrome) {
_myAvatar.setWantColor(!wantsMonochrome); _myAvatar.setWantColor(!wantsMonochrome);
} }
void Application::setWantsDelta(bool wantsDelta) { void Application::disableDeltaSending(bool disableDeltaSending) {
_myAvatar.setWantDelta(wantsDelta); _myAvatar.setWantDelta(!disableDeltaSending);
} }
void Application::disableOcclusionCulling(bool disableOcclusionCulling) { void Application::disableOcclusionCulling(bool disableOcclusionCulling) {
@ -1252,11 +1261,11 @@ void Application::updateVoxelModeActions() {
} }
} }
void Application::sendVoxelEditMessage(PACKET_HEADER header, VoxelDetail& detail) { void Application::sendVoxelEditMessage(PACKET_TYPE type, VoxelDetail& detail) {
unsigned char* bufferOut; unsigned char* bufferOut;
int sizeOut; int sizeOut;
if (createVoxelEditMessage(header, 0, 1, &detail, bufferOut, sizeOut)){ if (createVoxelEditMessage(type, 0, 1, &detail, bufferOut, sizeOut)){
Application::controlledBroadcastToNodes(bufferOut, sizeOut, & NODE_TYPE_VOXEL_SERVER, 1); Application::controlledBroadcastToNodes(bufferOut, sizeOut, & NODE_TYPE_VOXEL_SERVER, 1);
delete[] bufferOut; delete[] bufferOut;
} }
@ -1343,7 +1352,8 @@ bool Application::sendVoxelsOperation(VoxelNode* node, void* extraData) {
// if we have room don't have room in the buffer, then send the previously generated message first // if we have room don't have room in the buffer, then send the previously generated message first
if (args->bufferInUse + codeAndColorLength > MAXIMUM_EDIT_VOXEL_MESSAGE_SIZE) { if (args->bufferInUse + codeAndColorLength > MAXIMUM_EDIT_VOXEL_MESSAGE_SIZE) {
controlledBroadcastToNodes(args->messageBuffer, args->bufferInUse, & NODE_TYPE_VOXEL_SERVER, 1); controlledBroadcastToNodes(args->messageBuffer, args->bufferInUse, & NODE_TYPE_VOXEL_SERVER, 1);
args->bufferInUse = sizeof(PACKET_HEADER_SET_VOXEL_DESTRUCTIVE) + sizeof(unsigned short int); // reset args->bufferInUse = numBytesForPacketHeader((unsigned char*) &PACKET_TYPE_SET_VOXEL_DESTRUCTIVE)
+ sizeof(unsigned short int); // reset
} }
// copy this node's code color details into our buffer. // copy this node's code color details into our buffer.
@ -1410,10 +1420,12 @@ void Application::importVoxels() {
// the server as an set voxel message, this will also rebase the voxels to the new location // the server as an set voxel message, this will also rebase the voxels to the new location
unsigned char* calculatedOctCode = NULL; unsigned char* calculatedOctCode = NULL;
SendVoxelsOperationArgs args; SendVoxelsOperationArgs args;
args.messageBuffer[0] = PACKET_HEADER_SET_VOXEL_DESTRUCTIVE;
unsigned short int* sequenceAt = (unsigned short int*)&args.messageBuffer[sizeof(PACKET_HEADER_SET_VOXEL_DESTRUCTIVE)]; int numBytesPacketHeader = populateTypeAndVersion(args.messageBuffer, PACKET_TYPE_SET_VOXEL_DESTRUCTIVE);
unsigned short int* sequenceAt = (unsigned short int*)&args.messageBuffer[numBytesPacketHeader];
*sequenceAt = 0; *sequenceAt = 0;
args.bufferInUse = sizeof(PACKET_HEADER_SET_VOXEL_DESTRUCTIVE) + sizeof(unsigned short int); // set to command + sequence args.bufferInUse = numBytesPacketHeader + sizeof(unsigned short int); // set to command + sequence
// we only need the selected voxel to get the newBaseOctCode, which we can actually calculate from the // we only need the selected voxel to get the newBaseOctCode, which we can actually calculate from the
// voxel size/position details. // voxel size/position details.
@ -1426,7 +1438,7 @@ void Application::importVoxels() {
importVoxels.recurseTreeWithOperation(sendVoxelsOperation, &args); importVoxels.recurseTreeWithOperation(sendVoxelsOperation, &args);
// If we have voxels left in the packet, then send the packet // If we have voxels left in the packet, then send the packet
if (args.bufferInUse > (sizeof(PACKET_HEADER_SET_VOXEL_DESTRUCTIVE) + sizeof(unsigned short int))) { if (args.bufferInUse > (numBytesPacketHeader + sizeof(unsigned short int))) {
controlledBroadcastToNodes(args.messageBuffer, args.bufferInUse, & NODE_TYPE_VOXEL_SERVER, 1); controlledBroadcastToNodes(args.messageBuffer, args.bufferInUse, & NODE_TYPE_VOXEL_SERVER, 1);
} }
@ -1461,10 +1473,12 @@ void Application::pasteVoxels() {
// Recurse the clipboard tree, where everything is root relative, and send all the colored voxels to // Recurse the clipboard tree, where everything is root relative, and send all the colored voxels to
// the server as an set voxel message, this will also rebase the voxels to the new location // the server as an set voxel message, this will also rebase the voxels to the new location
SendVoxelsOperationArgs args; SendVoxelsOperationArgs args;
args.messageBuffer[0] = PACKET_HEADER_SET_VOXEL_DESTRUCTIVE;
unsigned short int* sequenceAt = (unsigned short int*)&args.messageBuffer[sizeof(PACKET_HEADER_SET_VOXEL_DESTRUCTIVE)]; int numBytesPacketHeader = populateTypeAndVersion(args.messageBuffer, PACKET_TYPE_SET_VOXEL_DESTRUCTIVE);
unsigned short int* sequenceAt = (unsigned short int*)&args.messageBuffer[numBytesPacketHeader];
*sequenceAt = 0; *sequenceAt = 0;
args.bufferInUse = sizeof(PACKET_HEADER_SET_VOXEL_DESTRUCTIVE) + sizeof(unsigned short int); // set to command + sequence args.bufferInUse = numBytesPacketHeader + sizeof(unsigned short int); // set to command + sequence
// we only need the selected voxel to get the newBaseOctCode, which we can actually calculate from the // we only need the selected voxel to get the newBaseOctCode, which we can actually calculate from the
// voxel size/position details. If we don't have an actual selectedNode then use the mouseVoxel to create a // voxel size/position details. If we don't have an actual selectedNode then use the mouseVoxel to create a
@ -1478,7 +1492,7 @@ void Application::pasteVoxels() {
_clipboardTree.recurseTreeWithOperation(sendVoxelsOperation, &args); _clipboardTree.recurseTreeWithOperation(sendVoxelsOperation, &args);
// If we have voxels left in the packet, then send the packet // If we have voxels left in the packet, then send the packet
if (args.bufferInUse > (sizeof(PACKET_HEADER_SET_VOXEL_DESTRUCTIVE) + sizeof(unsigned short int))) { if (args.bufferInUse > (numBytesPacketHeader + sizeof(unsigned short int))) {
controlledBroadcastToNodes(args.messageBuffer, args.bufferInUse, & NODE_TYPE_VOXEL_SERVER, 1); controlledBroadcastToNodes(args.messageBuffer, args.bufferInUse, & NODE_TYPE_VOXEL_SERVER, 1);
} }
@ -1625,9 +1639,11 @@ void Application::initMenu() {
renderDebugMenu->addAction("FALSE Color Occluded V2 Voxels", this, SLOT(doFalseColorizeOccludedV2()), Qt::CTRL | Qt::Key_P); renderDebugMenu->addAction("FALSE Color Occluded V2 Voxels", this, SLOT(doFalseColorizeOccludedV2()), Qt::CTRL | Qt::Key_P);
renderDebugMenu->addAction("Show TRUE Colors", this, SLOT(doTrueVoxelColors()), Qt::CTRL | Qt::Key_T); renderDebugMenu->addAction("Show TRUE Colors", this, SLOT(doTrueVoxelColors()), Qt::CTRL | Qt::Key_T);
debugMenu->addAction("Wants Monochrome", this, SLOT(setWantsMonochrome(bool)))->setCheckable(true);
debugMenu->addAction("Wants View Delta Sending", this, SLOT(setWantsDelta(bool)))->setCheckable(true);
(_shouldLowPassFilter = debugMenu->addAction("Test: LowPass filter"))->setCheckable(true); (_shouldLowPassFilter = debugMenu->addAction("Test: LowPass filter"))->setCheckable(true);
debugMenu->addAction("Wants Monochrome", this, SLOT(setWantsMonochrome(bool)))->setCheckable(true);
debugMenu->addAction("Use Lower Resolution While Moving", this, SLOT(setWantsLowResMoving(bool)))->setCheckable(true);
debugMenu->addAction("Disable Delta Sending", this, SLOT(disableDeltaSending(bool)))->setCheckable(true);
debugMenu->addAction("Disable Occlusion Culling", this, SLOT(disableOcclusionCulling(bool)), debugMenu->addAction("Disable Occlusion Culling", this, SLOT(disableOcclusionCulling(bool)),
Qt::SHIFT | Qt::Key_C)->setCheckable(true); Qt::SHIFT | Qt::Key_C)->setCheckable(true);
@ -2021,10 +2037,11 @@ void Application::updateAvatar(float deltaTime) {
_headMouseY = max(_headMouseY, 0); _headMouseY = max(_headMouseY, 0);
_headMouseY = min(_headMouseY, _glWidget->height()); _headMouseY = min(_headMouseY, _glWidget->height());
// Set lookAtPosition if an avatar is at the center of the screen const float MIDPOINT_OF_SCREEN = 0.5;
// Set lookAtPosition if an avatar is at the center of the screen
glm::vec3 screenCenterRayOrigin, screenCenterRayDirection; glm::vec3 screenCenterRayOrigin, screenCenterRayDirection;
_viewFrustum.computePickRay(0.5, 0.5, screenCenterRayOrigin, screenCenterRayDirection); _viewFrustum.computePickRay(MIDPOINT_OF_SCREEN, MIDPOINT_OF_SCREEN, screenCenterRayOrigin, screenCenterRayDirection);
glm::vec3 eyePosition; glm::vec3 eyePosition;
if (isLookingAtOtherAvatar(screenCenterRayOrigin, screenCenterRayDirection, eyePosition)) { if (isLookingAtOtherAvatar(screenCenterRayOrigin, screenCenterRayDirection, eyePosition)) {
@ -2068,7 +2085,8 @@ void Application::updateAvatar(float deltaTime) {
unsigned char broadcastString[200]; unsigned char broadcastString[200];
unsigned char* endOfBroadcastStringWrite = broadcastString; unsigned char* endOfBroadcastStringWrite = broadcastString;
*(endOfBroadcastStringWrite++) = PACKET_HEADER_HEAD_DATA; endOfBroadcastStringWrite += populateTypeAndVersion(endOfBroadcastStringWrite, PACKET_TYPE_HEAD_DATA);
endOfBroadcastStringWrite += packNodeId(endOfBroadcastStringWrite, nodeList->getOwnerID()); endOfBroadcastStringWrite += packNodeId(endOfBroadcastStringWrite, nodeList->getOwnerID());
endOfBroadcastStringWrite += _myAvatar.getBroadcastData(endOfBroadcastStringWrite); endOfBroadcastStringWrite += _myAvatar.getBroadcastData(endOfBroadcastStringWrite);
@ -2098,8 +2116,8 @@ void Application::updateAvatar(float deltaTime) {
_paintingVoxel.y >= 0.0 && _paintingVoxel.y <= 1.0 && _paintingVoxel.y >= 0.0 && _paintingVoxel.y <= 1.0 &&
_paintingVoxel.z >= 0.0 && _paintingVoxel.z <= 1.0) { _paintingVoxel.z >= 0.0 && _paintingVoxel.z <= 1.0) {
PACKET_HEADER message = (_destructiveAddVoxel->isChecked() ? PACKET_TYPE message = (_destructiveAddVoxel->isChecked() ?
PACKET_HEADER_SET_VOXEL_DESTRUCTIVE : PACKET_HEADER_SET_VOXEL); PACKET_TYPE_SET_VOXEL_DESTRUCTIVE : PACKET_TYPE_SET_VOXEL);
sendVoxelEditMessage(message, _paintingVoxel); sendVoxelEditMessage(message, _paintingVoxel);
} }
} }
@ -2981,8 +2999,8 @@ void Application::shiftPaintingColor() {
void Application::maybeEditVoxelUnderCursor() { void Application::maybeEditVoxelUnderCursor() {
if (_addVoxelMode->isChecked() || _colorVoxelMode->isChecked()) { if (_addVoxelMode->isChecked() || _colorVoxelMode->isChecked()) {
if (_mouseVoxel.s != 0) { if (_mouseVoxel.s != 0) {
PACKET_HEADER message = (_destructiveAddVoxel->isChecked() ? PACKET_TYPE message = (_destructiveAddVoxel->isChecked() ?
PACKET_HEADER_SET_VOXEL_DESTRUCTIVE : PACKET_HEADER_SET_VOXEL); PACKET_TYPE_SET_VOXEL_DESTRUCTIVE : PACKET_TYPE_SET_VOXEL);
sendVoxelEditMessage(message, _mouseVoxel); sendVoxelEditMessage(message, _mouseVoxel);
// create the voxel locally so it appears immediately // create the voxel locally so it appears immediately
@ -3055,7 +3073,7 @@ void Application::maybeEditVoxelUnderCursor() {
void Application::deleteVoxelUnderCursor() { void Application::deleteVoxelUnderCursor() {
if (_mouseVoxel.s != 0) { if (_mouseVoxel.s != 0) {
// sending delete to the server is sufficient, server will send new version so we see updates soon enough // sending delete to the server is sufficient, server will send new version so we see updates soon enough
sendVoxelEditMessage(PACKET_HEADER_ERASE_VOXEL, _mouseVoxel); sendVoxelEditMessage(PACKET_TYPE_ERASE_VOXEL, _mouseVoxel);
AudioInjector* voxelInjector = AudioInjectionManager::injectorWithCapacity(5000); AudioInjector* voxelInjector = AudioInjectionManager::injectorWithCapacity(5000);
voxelInjector->setPosition(glm::vec3(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z)); voxelInjector->setPosition(glm::vec3(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z));
// voxelInjector->setBearing(0); //straight down the z axis // voxelInjector->setBearing(0); //straight down the z axis
@ -3165,36 +3183,39 @@ void* Application::networkReceive(void* args) {
app->_packetCount++; app->_packetCount++;
app->_bytesCount += bytesReceived; app->_bytesCount += bytesReceived;
switch (app->_incomingPacket[0]) { if (packetVersionMatch(app->_incomingPacket)) {
case PACKET_HEADER_TRANSMITTER_DATA_V2: // only process this packet if we have a match on the packet version
// V2 = IOS transmitter app switch (app->_incomingPacket[0]) {
app->_myTransmitter.processIncomingData(app->_incomingPacket, bytesReceived); case PACKET_TYPE_TRANSMITTER_DATA_V2:
// V2 = IOS transmitter app
app->_myTransmitter.processIncomingData(app->_incomingPacket, bytesReceived);
break; break;
case PACKET_HEADER_MIXED_AUDIO: case PACKET_TYPE_MIXED_AUDIO:
app->_audio.addReceivedAudioToBuffer(app->_incomingPacket, bytesReceived); app->_audio.addReceivedAudioToBuffer(app->_incomingPacket, bytesReceived);
break; break;
case PACKET_HEADER_VOXEL_DATA: case PACKET_TYPE_VOXEL_DATA:
case PACKET_HEADER_VOXEL_DATA_MONOCHROME: case PACKET_TYPE_VOXEL_DATA_MONOCHROME:
case PACKET_HEADER_Z_COMMAND: case PACKET_TYPE_Z_COMMAND:
case PACKET_HEADER_ERASE_VOXEL: case PACKET_TYPE_ERASE_VOXEL:
app->_voxels.parseData(app->_incomingPacket, bytesReceived); app->_voxels.parseData(app->_incomingPacket, bytesReceived);
break; break;
case PACKET_HEADER_ENVIRONMENT_DATA: case PACKET_TYPE_ENVIRONMENT_DATA:
app->_environment.parseData(&senderAddress, app->_incomingPacket, bytesReceived); app->_environment.parseData(&senderAddress, app->_incomingPacket, bytesReceived);
break; break;
case PACKET_HEADER_BULK_AVATAR_DATA: case PACKET_TYPE_BULK_AVATAR_DATA:
NodeList::getInstance()->processBulkNodeData(&senderAddress, NodeList::getInstance()->processBulkNodeData(&senderAddress,
app->_incomingPacket, app->_incomingPacket,
bytesReceived); bytesReceived);
getInstance()->_bandwidthMeter.inputStream(BandwidthMeter::AVATARS).updateValue(bytesReceived); getInstance()->_bandwidthMeter.inputStream(BandwidthMeter::AVATARS).updateValue(bytesReceived);
break; break;
case PACKET_HEADER_AVATAR_VOXEL_URL: case PACKET_TYPE_AVATAR_VOXEL_URL:
processAvatarVoxelURLMessage(app->_incomingPacket, bytesReceived); processAvatarVoxelURLMessage(app->_incomingPacket, bytesReceived);
break; break;
default: default:
NodeList::getInstance()->processNodeData(&senderAddress, app->_incomingPacket, bytesReceived); NodeList::getInstance()->processNodeData(&senderAddress, app->_incomingPacket, bytesReceived);
break; break;
}
} }
} else if (!app->_enableNetworkThread) { } else if (!app->_enableNetworkThread) {
break; break;

View file

@ -136,7 +136,8 @@ private slots:
void doTrueVoxelColors(); void doTrueVoxelColors();
void doTreeStats(); void doTreeStats();
void setWantsMonochrome(bool wantsMonochrome); void setWantsMonochrome(bool wantsMonochrome);
void setWantsDelta(bool wantsDelta); void setWantsLowResMoving(bool wantsLowResMoving);
void disableDeltaSending(bool disableDeltaSending);
void disableOcclusionCulling(bool disableOcclusionCulling); void disableOcclusionCulling(bool disableOcclusionCulling);
void updateVoxelModeActions(); void updateVoxelModeActions();
void decreaseVoxelSize(); void decreaseVoxelSize();
@ -170,7 +171,7 @@ private:
static void sendVoxelServerAddScene(); static void sendVoxelServerAddScene();
static bool sendVoxelsOperation(VoxelNode* node, void* extraData); static bool sendVoxelsOperation(VoxelNode* node, void* extraData);
static void sendVoxelEditMessage(PACKET_HEADER header, VoxelDetail& detail); static void sendVoxelEditMessage(PACKET_TYPE type, VoxelDetail& detail);
static void sendAvatarVoxelURLMessage(const QUrl& url); static void sendAvatarVoxelURLMessage(const QUrl& url);
static void processAvatarVoxelURLMessage(unsigned char *packetData, size_t dataBytes); static void processAvatarVoxelURLMessage(unsigned char *packetData, size_t dataBytes);
static void sendPingPackets(); static void sendPingPackets();

View file

@ -99,16 +99,18 @@ inline void Audio::performIO(int16_t* inputLeft, int16_t* outputLeft, int16_t* o
glm::vec3 headPosition = interfaceAvatar->getHeadJointPosition(); glm::vec3 headPosition = interfaceAvatar->getHeadJointPosition();
glm::quat headOrientation = interfaceAvatar->getHead().getOrientation(); glm::quat headOrientation = interfaceAvatar->getHead().getOrientation();
int leadingBytes = sizeof(PACKET_HEADER_MICROPHONE_AUDIO_NO_ECHO) + sizeof(headPosition) + sizeof(headOrientation); int numBytesPacketHeader = numBytesForPacketHeader((unsigned char*) &PACKET_TYPE_MICROPHONE_AUDIO_NO_ECHO);
int leadingBytes = numBytesPacketHeader + sizeof(headPosition) + sizeof(headOrientation);
// we need the amount of bytes in the buffer + 1 for type // we need the amount of bytes in the buffer + 1 for type
// + 12 for 3 floats for position + float for bearing + 1 attenuation byte // + 12 for 3 floats for position + float for bearing + 1 attenuation byte
unsigned char dataPacket[BUFFER_LENGTH_BYTES_PER_CHANNEL + leadingBytes]; unsigned char dataPacket[BUFFER_LENGTH_BYTES_PER_CHANNEL + leadingBytes];
dataPacket[0] = (Application::getInstance()->shouldEchoAudio()) PACKET_TYPE packetType = (Application::getInstance()->shouldEchoAudio())
? PACKET_HEADER_MICROPHONE_AUDIO_WITH_ECHO ? PACKET_TYPE_MICROPHONE_AUDIO_WITH_ECHO
: PACKET_HEADER_MICROPHONE_AUDIO_NO_ECHO; : PACKET_TYPE_MICROPHONE_AUDIO_NO_ECHO;
unsigned char *currentPacketPtr = dataPacket + 1;
unsigned char* currentPacketPtr = dataPacket + populateTypeAndVersion(dataPacket, packetType);
// memcpy the three float positions // memcpy the three float positions
memcpy(currentPacketPtr, &headPosition, sizeof(headPosition)); memcpy(currentPacketPtr, &headPosition, sizeof(headPosition));
@ -446,10 +448,10 @@ void Audio::addReceivedAudioToBuffer(unsigned char* receivedData, int receivedBy
//printf("Got audio packet %d\n", _packetsReceivedThisPlayback); //printf("Got audio packet %d\n", _packetsReceivedThisPlayback);
_ringBuffer.parseData((unsigned char*) receivedData, PACKET_LENGTH_BYTES + sizeof(PACKET_HEADER)); _ringBuffer.parseData((unsigned char*) receivedData, PACKET_LENGTH_BYTES + sizeof(PACKET_TYPE));
Application::getInstance()->getBandwidthMeter()->inputStream(BandwidthMeter::AUDIO) Application::getInstance()->getBandwidthMeter()->inputStream(BandwidthMeter::AUDIO)
.updateValue(PACKET_LENGTH_BYTES + sizeof(PACKET_HEADER)); .updateValue(PACKET_LENGTH_BYTES + sizeof(PACKET_TYPE));
_lastReceiveTime = currentReceiveTime; _lastReceiveTime = currentReceiveTime;
} }

View file

@ -10,6 +10,7 @@
#include <QtDebug> #include <QtDebug>
#include <GeometryUtil.h> #include <GeometryUtil.h>
#include <PacketHeaders.h>
#include <SharedUtil.h> #include <SharedUtil.h>
#include "Camera.h" #include "Camera.h"
@ -138,8 +139,10 @@ bool Environment::findCapsulePenetration(const glm::vec3& start, const glm::vec3
int Environment::parseData(sockaddr *senderAddress, unsigned char* sourceBuffer, int numBytes) { int Environment::parseData(sockaddr *senderAddress, unsigned char* sourceBuffer, int numBytes) {
// push past the packet header // push past the packet header
unsigned char* start = sourceBuffer; unsigned char* start = sourceBuffer;
sourceBuffer++;
numBytes--; int numBytesPacketHeader = numBytesForPacketHeader(sourceBuffer);
sourceBuffer += numBytesPacketHeader;
numBytes -= numBytesPacketHeader;
// get the lock for the duration of the call // get the lock for the duration of the call
QMutexLocker locker(&_mutex); QMutexLocker locker(&_mutex);

View file

@ -31,7 +31,7 @@ const short NO_READ_MAXIMUM_MSECS = 3000;
const int GRAVITY_SAMPLES = 60; // Use the first few samples to baseline values const int GRAVITY_SAMPLES = 60; // Use the first few samples to baseline values
const int NORTH_SAMPLES = 30; const int NORTH_SAMPLES = 30;
const int ACCELERATION_SENSOR_FUSION_SAMPLES = 20; const int ACCELERATION_SENSOR_FUSION_SAMPLES = 20;
const int COMPASS_SENSOR_FUSION_SAMPLES = 200; const int COMPASS_SENSOR_FUSION_SAMPLES = 100;
const int LONG_TERM_RATE_SAMPLES = 1000; const int LONG_TERM_RATE_SAMPLES = 1000;
const bool USING_INVENSENSE_MPU9150 = 1; const bool USING_INVENSENSE_MPU9150 = 1;
@ -383,7 +383,7 @@ void SerialInterface::resetSerial() {
glm::vec3 SerialInterface::recenterCompass(const glm::vec3& compass) { glm::vec3 SerialInterface::recenterCompass(const glm::vec3& compass) {
// compensate for "hard iron" distortion by subtracting the midpoint on each axis; see // compensate for "hard iron" distortion by subtracting the midpoint on each axis; see
// http://www.sensorsmag.com/sensors/motion-velocity-displacement/compensating-tilt-hard-iron-and-soft-iron-effects-6475 // http://www.sensorsmag.com/sensors/motion-velocity-displacement/compensating-tilt-hard-iron-and-soft-iron-effects-6475
return compass - (_compassMinima + _compassMaxima) * 0.5f; return (compass - (_compassMinima + _compassMaxima) * 0.5f) / (_compassMaxima - _compassMinima);
} }

View file

@ -33,8 +33,8 @@ public:
_estimatedVelocity(0, 0, 0), _estimatedVelocity(0, 0, 0),
_lastAcceleration(0, 0, 0), _lastAcceleration(0, 0, 0),
_lastRotationRates(0, 0, 0), _lastRotationRates(0, 0, 0),
_compassMinima(-235, -132, -184), // experimentally derived initial values follow _compassMinima(-211, -132, -186),
_compassMaxima(83, 155, 120), _compassMaxima(89, 95, 98),
_angularVelocityToLinearAccel( _angularVelocityToLinearAccel(
0.003f, -0.001f, -0.006f, 0.003f, -0.001f, -0.006f,
-0.005f, -0.001f, -0.006f, -0.005f, -0.001f, -0.006f,

View file

@ -3,15 +3,20 @@
// hifi // hifi
// //
// Created by Philip Rosedale on 5/20/13. // Created by Philip Rosedale on 5/20/13.
// // Copyright (c) 2013 HighFidelity, Inc. All rights reserved.
// //
#include "Transmitter.h"
#include "InterfaceConfig.h"
#include "Util.h"
#include <cstring> #include <cstring>
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include <PacketHeaders.h>
#include "InterfaceConfig.h"
#include "Log.h" #include "Log.h"
#include "Transmitter.h"
#include "Util.h"
const float DELTA_TIME = 1.f / 60.f; const float DELTA_TIME = 1.f / 60.f;
const float DECAY_RATE = 0.15f; const float DECAY_RATE = 0.15f;
@ -45,7 +50,9 @@ void Transmitter::resetLevels() {
} }
void Transmitter::processIncomingData(unsigned char* packetData, int numBytes) { void Transmitter::processIncomingData(unsigned char* packetData, int numBytes) {
const int PACKET_HEADER_SIZE = 1; // Packet's first byte is 'T' // Packet's first byte is 'T'
int numBytesPacketHeader = numBytesForPacketHeader(packetData);
const int ROTATION_MARKER_SIZE = 1; // 'R' = Rotation (clockwise about x,y,z) const int ROTATION_MARKER_SIZE = 1; // 'R' = Rotation (clockwise about x,y,z)
const int ACCELERATION_MARKER_SIZE = 1; // 'A' = Acceleration (x,y,z) const int ACCELERATION_MARKER_SIZE = 1; // 'A' = Acceleration (x,y,z)
if (!_lastReceivedPacket) { if (!_lastReceivedPacket) {
@ -53,10 +60,10 @@ void Transmitter::processIncomingData(unsigned char* packetData, int numBytes) {
} }
gettimeofday(_lastReceivedPacket, NULL); gettimeofday(_lastReceivedPacket, NULL);
if (numBytes == PACKET_HEADER_SIZE + ROTATION_MARKER_SIZE + ACCELERATION_MARKER_SIZE if (numBytes == numBytesPacketHeader + ROTATION_MARKER_SIZE + ACCELERATION_MARKER_SIZE
+ sizeof(_lastRotationRate) + sizeof(_lastAcceleration) + sizeof(_lastRotationRate) + sizeof(_lastAcceleration)
+ sizeof(_touchState.x) + sizeof(_touchState.y) + sizeof(_touchState.state)) { + sizeof(_touchState.x) + sizeof(_touchState.y) + sizeof(_touchState.state)) {
unsigned char* packetDataPosition = &packetData[PACKET_HEADER_SIZE + ROTATION_MARKER_SIZE]; unsigned char* packetDataPosition = packetData + numBytesPacketHeader + ROTATION_MARKER_SIZE;
memcpy(&_lastRotationRate, packetDataPosition, sizeof(_lastRotationRate)); memcpy(&_lastRotationRate, packetDataPosition, sizeof(_lastRotationRate));
packetDataPosition += sizeof(_lastRotationRate) + ACCELERATION_MARKER_SIZE; packetDataPosition += sizeof(_lastRotationRate) + ACCELERATION_MARKER_SIZE;
memcpy(&_lastAcceleration, packetDataPosition, sizeof(_lastAcceleration)); memcpy(&_lastAcceleration, packetDataPosition, sizeof(_lastAcceleration));

View file

@ -3,7 +3,7 @@
// hifi // hifi
// //
// Created by Philip Rosedale on 5/20/13. // Created by Philip Rosedale on 5/20/13.
// // Copyright (c) 2013 HighFidelity, Inc. All rights reserved.
// //
#ifndef __hifi__Transmitter__ #ifndef __hifi__Transmitter__

View file

@ -113,32 +113,31 @@ float VoxelSystem::getVoxelsBytesReadPerSecondAverage() {
int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) { int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) {
unsigned char command = *sourceBuffer; unsigned char command = *sourceBuffer;
unsigned char *voxelData = sourceBuffer + 1; int numBytesPacketHeader = numBytesForPacketHeader(sourceBuffer);
unsigned char* voxelData = sourceBuffer + numBytesPacketHeader;
pthread_mutex_lock(&_treeLock); pthread_mutex_lock(&_treeLock);
switch(command) { switch(command) {
case PACKET_HEADER_VOXEL_DATA: case PACKET_TYPE_VOXEL_DATA: {
{
PerformanceWarning warn(_renderWarningsOn, "readBitstreamToTree()"); PerformanceWarning warn(_renderWarningsOn, "readBitstreamToTree()");
// ask the VoxelTree to read the bitstream into the tree // ask the VoxelTree to read the bitstream into the tree
_tree->readBitstreamToTree(voxelData, numBytes - 1, WANT_COLOR, WANT_EXISTS_BITS); _tree->readBitstreamToTree(voxelData, numBytes - numBytesPacketHeader, WANT_COLOR, WANT_EXISTS_BITS);
} }
break; break;
case PACKET_HEADER_VOXEL_DATA_MONOCHROME: case PACKET_TYPE_VOXEL_DATA_MONOCHROME: {
{
PerformanceWarning warn(_renderWarningsOn, "readBitstreamToTree()"); PerformanceWarning warn(_renderWarningsOn, "readBitstreamToTree()");
// ask the VoxelTree to read the MONOCHROME bitstream into the tree // ask the VoxelTree to read the MONOCHROME bitstream into the tree
_tree->readBitstreamToTree(voxelData, numBytes - 1, NO_COLOR, WANT_EXISTS_BITS); _tree->readBitstreamToTree(voxelData, numBytes - numBytesPacketHeader, NO_COLOR, WANT_EXISTS_BITS);
} }
break; break;
case PACKET_HEADER_Z_COMMAND: case PACKET_TYPE_Z_COMMAND:
// the Z command is a special command that allows the sender to send high level semantic // the Z command is a special command that allows the sender to send high level semantic
// requests, like erase all, or add sphere scene, different receivers may handle these // requests, like erase all, or add sphere scene, different receivers may handle these
// messages differently // messages differently
char* packetData = (char *)sourceBuffer; char* packetData = (char *)sourceBuffer;
char* command = &packetData[1]; // start of the command char* command = &packetData[numBytesPacketHeader]; // start of the command
int commandLength = strlen(command); // commands are null terminated strings int commandLength = strlen(command); // commands are null terminated strings
int totalLength = 1+commandLength+1; int totalLength = 1+commandLength+1;
@ -892,13 +891,11 @@ bool VoxelSystem::removeOutOfViewOperation(VoxelNode* node, void* extraData) {
bool VoxelSystem::isViewChanging() { bool VoxelSystem::isViewChanging() {
bool result = false; // assume the best bool result = false; // assume the best
/** TEMPORARY HACK ******
// If our viewFrustum has changed since our _lastKnowViewFrustum // If our viewFrustum has changed since our _lastKnowViewFrustum
if (_viewFrustum && !_lastKnowViewFrustum.matches(_viewFrustum)) { if (!_lastKnowViewFrustum.matches(Application::getInstance()->getViewFrustum())) {
result = true; result = true;
_lastKnowViewFrustum = *_viewFrustum; // save last known _lastKnowViewFrustum = *Application::getInstance()->getViewFrustum(); // save last known
} }
**/
return result; return result;
} }

View file

@ -50,7 +50,7 @@ void Webcam::setEnabled(bool enabled) {
QMetaObject::invokeMethod(_grabber, "grabFrame"); QMetaObject::invokeMethod(_grabber, "grabFrame");
} else { } else {
_grabberThread.quit(); QMetaObject::invokeMethod(_grabber, "shutdown");
_active = false; _active = false;
} }
} }
@ -267,8 +267,8 @@ FrameGrabber::FrameGrabber() : _initialized(false), _capture(0), _searchWindow(0
} }
FrameGrabber::~FrameGrabber() { FrameGrabber::~FrameGrabber() {
if (_capture != 0) { if (_initialized) {
cvReleaseCapture(&_capture); shutdown();
} }
} }
@ -366,6 +366,16 @@ void FrameGrabber::reset() {
#endif #endif
} }
void FrameGrabber::shutdown() {
if (_capture != 0) {
cvReleaseCapture(&_capture);
_capture = 0;
}
_initialized = false;
thread()->quit();
}
void FrameGrabber::grabFrame() { void FrameGrabber::grabFrame() {
if (!(_initialized || init())) { if (!(_initialized || init())) {
return; return;
@ -475,7 +485,7 @@ bool FrameGrabber::init() {
// load our face cascade // load our face cascade
switchToResourcesParentIfRequired(); switchToResourcesParentIfRequired();
if (!_faceCascade.load("resources/haarcascades/haarcascade_frontalface_alt.xml")) { if (_faceCascade.empty() && !_faceCascade.load("resources/haarcascades/haarcascade_frontalface_alt.xml")) {
printLog("Failed to load Haar cascade for face tracking.\n"); printLog("Failed to load Haar cascade for face tracking.\n");
return false; return false;
} }

View file

@ -94,6 +94,7 @@ public:
public slots: public slots:
void reset(); void reset();
void shutdown();
void grabFrame(); void grabFrame();
private: private:

View file

@ -70,7 +70,7 @@ void AudioInjector::injectAudio(UDPSocket* injectorSocket, sockaddr* destination
timeval startTime; timeval startTime;
// calculate the number of bytes required for additional data // calculate the number of bytes required for additional data
int leadingBytes = sizeof(PACKET_HEADER) int leadingBytes = numBytesForPacketHeader((unsigned char*) &PACKET_TYPE_INJECT_AUDIO)
+ sizeof(_streamIdentifier) + sizeof(_streamIdentifier)
+ sizeof(_position) + sizeof(_position)
+ sizeof(_orientation) + sizeof(_orientation)
@ -79,8 +79,7 @@ void AudioInjector::injectAudio(UDPSocket* injectorSocket, sockaddr* destination
unsigned char dataPacket[(BUFFER_LENGTH_SAMPLES_PER_CHANNEL * sizeof(int16_t)) + leadingBytes]; unsigned char dataPacket[(BUFFER_LENGTH_SAMPLES_PER_CHANNEL * sizeof(int16_t)) + leadingBytes];
dataPacket[0] = PACKET_HEADER_INJECT_AUDIO; unsigned char* currentPacketPtr = dataPacket + populateTypeAndVersion(dataPacket, PACKET_TYPE_INJECT_AUDIO);
unsigned char *currentPacketPtr = dataPacket + sizeof(PACKET_HEADER_INJECT_AUDIO);
// copy the identifier for this injector // copy the identifier for this injector
memcpy(currentPacketPtr, &_streamIdentifier, sizeof(_streamIdentifier)); memcpy(currentPacketPtr, &_streamIdentifier, sizeof(_streamIdentifier));

View file

@ -34,7 +34,8 @@ void AudioRingBuffer::reset() {
} }
int AudioRingBuffer::parseData(unsigned char* sourceBuffer, int numBytes) { int AudioRingBuffer::parseData(unsigned char* sourceBuffer, int numBytes) {
return parseAudioSamples(sourceBuffer + sizeof(PACKET_HEADER_MIXED_AUDIO), numBytes - sizeof(PACKET_HEADER_MIXED_AUDIO)); int numBytesPacketHeader = numBytesForPacketHeader(sourceBuffer);
return parseAudioSamples(sourceBuffer + numBytesPacketHeader, numBytes - numBytesPacketHeader);
} }
int AudioRingBuffer::parseAudioSamples(unsigned char* sourceBuffer, int numBytes) { int AudioRingBuffer::parseAudioSamples(unsigned char* sourceBuffer, int numBytes) {

View file

@ -33,7 +33,8 @@ AvatarData::AvatarData(Node* owningNode) :
_cameraFarClip(0.0f), _cameraFarClip(0.0f),
_keyState(NO_KEY_DOWN), _keyState(NO_KEY_DOWN),
_wantColor(true), _wantColor(true),
_wantDelta(false), _wantDelta(true),
_wantLowResMoving(false),
_wantOcclusionCulling(true), _wantOcclusionCulling(true),
_headData(NULL), _headData(NULL),
_handData(NULL) _handData(NULL)
@ -112,8 +113,9 @@ int AvatarData::getBroadcastData(unsigned char* destinationBuffer) {
// bitMask of less than byte wide items // bitMask of less than byte wide items
unsigned char bitItems = 0; unsigned char bitItems = 0;
if (_wantColor) { setAtBit(bitItems, WANT_COLOR_AT_BIT); } if (_wantLowResMoving) { setAtBit(bitItems, WANT_LOW_RES_MOVING_BIT); }
if (_wantDelta) { setAtBit(bitItems, WANT_DELTA_AT_BIT); } if (_wantColor) { setAtBit(bitItems, WANT_COLOR_AT_BIT); }
if (_wantDelta) { setAtBit(bitItems, WANT_DELTA_AT_BIT); }
if (_wantOcclusionCulling) { setAtBit(bitItems, WANT_OCCLUSION_CULLING_BIT); } if (_wantOcclusionCulling) { setAtBit(bitItems, WANT_OCCLUSION_CULLING_BIT); }
// key state // key state
@ -174,12 +176,13 @@ int AvatarData::parseData(unsigned char* sourceBuffer, int numBytes) {
} }
// increment to push past the packet header // increment to push past the packet header
sourceBuffer += sizeof(PACKET_HEADER_HEAD_DATA); int numBytesPacketHeader = numBytesForPacketHeader(sourceBuffer);
sourceBuffer += numBytesPacketHeader;
unsigned char* startPosition = sourceBuffer; unsigned char* startPosition = sourceBuffer;
// push past the node ID // push past the node ID
sourceBuffer += + sizeof(uint16_t); sourceBuffer += sizeof(uint16_t);
// Body world position // Body world position
memcpy(&_position, sourceBuffer, sizeof(float) * 3); memcpy(&_position, sourceBuffer, sizeof(float) * 3);
@ -238,8 +241,9 @@ int AvatarData::parseData(unsigned char* sourceBuffer, int numBytes) {
// voxel sending features... // voxel sending features...
unsigned char bitItems = 0; unsigned char bitItems = 0;
bitItems = (unsigned char)*sourceBuffer++; bitItems = (unsigned char)*sourceBuffer++;
_wantColor = oneAtBit(bitItems, WANT_COLOR_AT_BIT); _wantLowResMoving = oneAtBit(bitItems, WANT_LOW_RES_MOVING_BIT);
_wantDelta = oneAtBit(bitItems, WANT_DELTA_AT_BIT); _wantColor = oneAtBit(bitItems, WANT_COLOR_AT_BIT);
_wantDelta = oneAtBit(bitItems, WANT_DELTA_AT_BIT);
_wantOcclusionCulling = oneAtBit(bitItems, WANT_OCCLUSION_CULLING_BIT); _wantOcclusionCulling = oneAtBit(bitItems, WANT_OCCLUSION_CULLING_BIT);
// key state, stored as a semi-nibble in the bitItems // key state, stored as a semi-nibble in the bitItems

View file

@ -20,7 +20,7 @@
#include "HeadData.h" #include "HeadData.h"
#include "HandData.h" #include "HandData.h"
const int UNUSED_BIT = 0; // this bit is available to use const int WANT_LOW_RES_MOVING_BIT = 0;
const int WANT_COLOR_AT_BIT = 1; const int WANT_COLOR_AT_BIT = 1;
const int WANT_DELTA_AT_BIT = 2; const int WANT_DELTA_AT_BIT = 2;
const int KEY_STATE_START_BIT = 3; // 4th and 5th bits const int KEY_STATE_START_BIT = 3; // 4th and 5th bits
@ -91,11 +91,14 @@ public:
const std::string& chatMessage () const { return _chatMessage; } const std::string& chatMessage () const { return _chatMessage; }
// related to Voxel Sending strategies // related to Voxel Sending strategies
bool getWantColor() const { return _wantColor; } bool getWantColor() const { return _wantColor; }
bool getWantDelta() const { return _wantDelta; } bool getWantDelta() const { return _wantDelta; }
bool getWantLowResMoving() const { return _wantLowResMoving; }
bool getWantOcclusionCulling() const { return _wantOcclusionCulling; } bool getWantOcclusionCulling() const { return _wantOcclusionCulling; }
void setWantColor(bool wantColor) { _wantColor = wantColor; }
void setWantDelta(bool wantDelta) { _wantDelta = wantDelta; } void setWantColor(bool wantColor) { _wantColor = wantColor; }
void setWantDelta(bool wantDelta) { _wantDelta = wantDelta; }
void setWantLowResMoving(bool wantLowResMoving) { _wantLowResMoving = wantLowResMoving; }
void setWantOcclusionCulling(bool wantOcclusionCulling) { _wantOcclusionCulling = wantOcclusionCulling; } void setWantOcclusionCulling(bool wantOcclusionCulling) { _wantOcclusionCulling = wantOcclusionCulling; }
void setHeadData(HeadData* headData) { _headData = headData; } void setHeadData(HeadData* headData) { _headData = headData; }
@ -130,6 +133,7 @@ protected:
// voxel server sending items // voxel server sending items
bool _wantColor; bool _wantColor;
bool _wantDelta; bool _wantDelta;
bool _wantLowResMoving;
bool _wantOcclusionCulling; bool _wantOcclusionCulling;
std::vector<JointData> _joints; std::vector<JointData> _joints;

View file

@ -72,7 +72,6 @@ NodeList::~NodeList() {
// stop the spawned threads, if they were started // stop the spawned threads, if they were started
stopSilentNodeRemovalThread(); stopSilentNodeRemovalThread();
stopPingUnknownNodesThread();
pthread_mutex_destroy(&mutex); pthread_mutex_destroy(&mutex);
} }
@ -81,27 +80,29 @@ void NodeList::timePingReply(sockaddr *nodeAddress, unsigned char *packetData) {
for(NodeList::iterator node = begin(); node != end(); node++) { for(NodeList::iterator node = begin(); node != end(); node++) {
if (socketMatch(node->getPublicSocket(), nodeAddress) || if (socketMatch(node->getPublicSocket(), nodeAddress) ||
socketMatch(node->getLocalSocket(), nodeAddress)) { socketMatch(node->getLocalSocket(), nodeAddress)) {
int pingTime = usecTimestampNow() - *(uint64_t *)(packetData + 1);
int pingTime = usecTimestampNow() - *(uint64_t*)(packetData + numBytesForPacketHeader(packetData));
node->setPingMs(pingTime / 1000); node->setPingMs(pingTime / 1000);
break; break;
} }
} }
} }
void NodeList::processNodeData(sockaddr *senderAddress, unsigned char *packetData, size_t dataBytes) { void NodeList::processNodeData(sockaddr* senderAddress, unsigned char* packetData, size_t dataBytes) {
switch (((char *)packetData)[0]) { switch (packetData[0]) {
case PACKET_HEADER_DOMAIN: { case PACKET_TYPE_DOMAIN: {
processDomainServerList(packetData, dataBytes); processDomainServerList(packetData, dataBytes);
break; break;
} }
case PACKET_HEADER_PING: { case PACKET_TYPE_PING: {
char pingPacket[dataBytes]; char pingPacket[dataBytes];
memcpy(pingPacket, packetData, dataBytes); memcpy(pingPacket, packetData, dataBytes);
pingPacket[0] = PACKET_HEADER_PING_REPLY; populateTypeAndVersion((unsigned char*) pingPacket, PACKET_TYPE_PING_REPLY);
_nodeSocket.send(senderAddress, pingPacket, dataBytes); _nodeSocket.send(senderAddress, pingPacket, dataBytes);
break; break;
} }
case PACKET_HEADER_PING_REPLY: { case PACKET_TYPE_PING_REPLY: {
timePingReply(senderAddress, packetData); timePingReply(senderAddress, packetData);
break; break;
} }
@ -119,17 +120,22 @@ void NodeList::processBulkNodeData(sockaddr *senderAddress, unsigned char *packe
bulkSendNode->recordBytesReceived(numTotalBytes); bulkSendNode->recordBytesReceived(numTotalBytes);
} }
int numBytesPacketHeader = numBytesForPacketHeader(packetData);
unsigned char *startPosition = packetData; unsigned char *startPosition = packetData;
unsigned char *currentPosition = startPosition + 1; unsigned char *currentPosition = startPosition + numBytesPacketHeader;
unsigned char packetHolder[numTotalBytes]; unsigned char packetHolder[numTotalBytes];
packetHolder[0] = PACKET_HEADER_HEAD_DATA; // we've already verified packet version for the bulk packet, so all head data in the packet is also up to date
populateTypeAndVersion(packetHolder, PACKET_TYPE_HEAD_DATA);
uint16_t nodeID = -1; uint16_t nodeID = -1;
while ((currentPosition - startPosition) < numTotalBytes) { while ((currentPosition - startPosition) < numTotalBytes) {
unpackNodeId(currentPosition, &nodeID); unpackNodeId(currentPosition, &nodeID);
memcpy(packetHolder + 1, currentPosition, numTotalBytes - (currentPosition - startPosition)); memcpy(packetHolder + numBytesPacketHeader,
currentPosition,
numTotalBytes - (currentPosition - startPosition));
Node* matchingNode = nodeWithID(nodeID); Node* matchingNode = nodeWithID(nodeID);
@ -139,8 +145,8 @@ void NodeList::processBulkNodeData(sockaddr *senderAddress, unsigned char *packe
} }
currentPosition += updateNodeWithData(matchingNode, currentPosition += updateNodeWithData(matchingNode,
packetHolder, packetHolder,
numTotalBytes - (currentPosition - startPosition)); numTotalBytes - (currentPosition - startPosition));
} }
unlock(); unlock();
@ -213,6 +219,7 @@ void NodeList::setNodeTypesOfInterest(const char* nodeTypesOfInterest, int numNo
void NodeList::sendDomainServerCheckIn() { void NodeList::sendDomainServerCheckIn() {
static bool printedDomainServerIP = false; static bool printedDomainServerIP = false;
// Lookup the IP address of the domain server if we need to // Lookup the IP address of the domain server if we need to
if (atoi(DOMAIN_IP) == 0) { if (atoi(DOMAIN_IP) == 0) {
struct hostent* pHostInfo; struct hostent* pHostInfo;
@ -229,26 +236,32 @@ void NodeList::sendDomainServerCheckIn() {
printedDomainServerIP = true; printedDomainServerIP = true;
} }
// construct the DS check in packet if we need to
static unsigned char* checkInPacket = NULL; static unsigned char* checkInPacket = NULL;
static int checkInPacketSize; static int checkInPacketSize = 0;
// construct the DS check in packet if we need to
if (!checkInPacket) { if (!checkInPacket) {
int numBytesNodesOfInterest = _nodeTypesOfInterest ? strlen((char*) _nodeTypesOfInterest) : 0; int numBytesNodesOfInterest = _nodeTypesOfInterest ? strlen((char*) _nodeTypesOfInterest) : 0;
const int IP_ADDRESS_BYTES = 4;
// check in packet has header, node type, port, IP, node types of interest, null termination // check in packet has header, node type, port, IP, node types of interest, null termination
int numPacketBytes = sizeof(PACKET_HEADER) + sizeof(NODE_TYPE) + sizeof(uint16_t) + (sizeof(char) * 4) + int numPacketBytes = sizeof(PACKET_TYPE) + sizeof(PACKET_VERSION) + sizeof(NODE_TYPE) + sizeof(uint16_t) +
numBytesNodesOfInterest + sizeof(unsigned char); IP_ADDRESS_BYTES + numBytesNodesOfInterest + sizeof(unsigned char);
checkInPacket = new unsigned char[numPacketBytes]; checkInPacket = new unsigned char[numPacketBytes];
unsigned char* packetPosition = checkInPacket; unsigned char* packetPosition = checkInPacket;
*(packetPosition++) = (memchr(SOLO_NODE_TYPES, _ownerType, sizeof(SOLO_NODE_TYPES))) PACKET_TYPE nodePacketType = (memchr(SOLO_NODE_TYPES, _ownerType, sizeof(SOLO_NODE_TYPES)))
? PACKET_HEADER_DOMAIN_REPORT_FOR_DUTY ? PACKET_TYPE_DOMAIN_REPORT_FOR_DUTY
: PACKET_HEADER_DOMAIN_LIST_REQUEST; : PACKET_TYPE_DOMAIN_LIST_REQUEST;
int numHeaderBytes = populateTypeAndVersion(packetPosition, nodePacketType);
packetPosition += numHeaderBytes;
*(packetPosition++) = _ownerType; *(packetPosition++) = _ownerType;
packetPosition += packSocket(checkInPacket + sizeof(PACKET_HEADER) + sizeof(NODE_TYPE), packetPosition += packSocket(checkInPacket + numHeaderBytes + sizeof(NODE_TYPE),
getLocalAddress(), getLocalAddress(),
htons(_nodeSocket.getListeningPort())); htons(_nodeSocket.getListeningPort()));
@ -269,7 +282,7 @@ void NodeList::sendDomainServerCheckIn() {
_nodeSocket.send(DOMAIN_IP, DOMAINSERVER_PORT, checkInPacket, checkInPacketSize); _nodeSocket.send(DOMAIN_IP, DOMAINSERVER_PORT, checkInPacket, checkInPacketSize);
} }
int NodeList::processDomainServerList(unsigned char *packetData, size_t dataBytes) { int NodeList::processDomainServerList(unsigned char* packetData, size_t dataBytes) {
int readNodes = 0; int readNodes = 0;
char nodeType; char nodeType;
@ -281,16 +294,16 @@ int NodeList::processDomainServerList(unsigned char *packetData, size_t dataByte
sockaddr_in nodeLocalSocket; sockaddr_in nodeLocalSocket;
nodeLocalSocket.sin_family = AF_INET; nodeLocalSocket.sin_family = AF_INET;
unsigned char *readPtr = packetData + 1; unsigned char* readPtr = packetData + numBytesForPacketHeader(packetData);
unsigned char *startPtr = packetData; unsigned char* startPtr = packetData;
while((readPtr - startPtr) < dataBytes - sizeof(uint16_t)) { while((readPtr - startPtr) < dataBytes - sizeof(uint16_t)) {
nodeType = *readPtr++; nodeType = *readPtr++;
readPtr += unpackNodeId(readPtr, (uint16_t *)&nodeId); readPtr += unpackNodeId(readPtr, (uint16_t*) &nodeId);
readPtr += unpackSocket(readPtr, (sockaddr *)&nodePublicSocket); readPtr += unpackSocket(readPtr, (sockaddr*) &nodePublicSocket);
readPtr += unpackSocket(readPtr, (sockaddr *)&nodeLocalSocket); readPtr += unpackSocket(readPtr, (sockaddr*) &nodeLocalSocket);
addOrUpdateNode((sockaddr *)&nodePublicSocket, (sockaddr *)&nodeLocalSocket, nodeType, nodeId); addOrUpdateNode((sockaddr*) &nodePublicSocket, (sockaddr*) &nodeLocalSocket, nodeType, nodeId);
} }
// read out our ID from the packet // read out our ID from the packet
@ -401,46 +414,6 @@ Node* NodeList::soloNodeOfType(char nodeType) {
return NULL; return NULL;
} }
void *pingUnknownNodes(void *args) {
NodeList* nodeList = (NodeList*) args;
const int PING_INTERVAL_USECS = 1 * 1000000;
timeval lastSend;
while (!pingUnknownNodeThreadStopFlag) {
gettimeofday(&lastSend, NULL);
for(NodeList::iterator node = nodeList->begin();
node != nodeList->end();
node++) {
if (!node->getActiveSocket() && node->getPublicSocket() && node->getLocalSocket()) {
// ping both of the sockets for the node so we can figure out
// which socket we can use
nodeList->getNodeSocket()->send(node->getPublicSocket(), &PACKET_HEADER_PING, 1);
nodeList->getNodeSocket()->send(node->getLocalSocket(), &PACKET_HEADER_PING, 1);
}
}
int usecToSleep = PING_INTERVAL_USECS - (usecTimestampNow() - usecTimestamp(&lastSend));
if (usecToSleep > 0) {
usleep(usecToSleep);
}
}
return NULL;
}
void NodeList::startPingUnknownNodesThread() {
pthread_create(&pingUnknownNodesThread, NULL, pingUnknownNodes, (void *)this);
}
void NodeList::stopPingUnknownNodesThread() {
pingUnknownNodeThreadStopFlag = true;
pthread_join(pingUnknownNodesThread, NULL);
}
void *removeSilentNodes(void *args) { void *removeSilentNodes(void *args) {
NodeList* nodeList = (NodeList*) args; NodeList* nodeList = (NodeList*) args;
uint64_t checkTimeUSecs; uint64_t checkTimeUSecs;

View file

@ -89,8 +89,6 @@ public:
void startSilentNodeRemovalThread(); void startSilentNodeRemovalThread();
void stopSilentNodeRemovalThread(); void stopSilentNodeRemovalThread();
void startPingUnknownNodesThread();
void stopPingUnknownNodesThread();
friend class NodeListIterator; friend class NodeListIterator;
private: private:
@ -113,7 +111,6 @@ private:
uint16_t _lastNodeID; uint16_t _lastNodeID;
pthread_t removeSilentNodesThread; pthread_t removeSilentNodesThread;
pthread_t checkInWithDomainServerThread; pthread_t checkInWithDomainServerThread;
pthread_t pingUnknownNodesThread;
pthread_mutex_t mutex; pthread_mutex_t mutex;
void handlePingReply(sockaddr *nodeAddress); void handlePingReply(sockaddr *nodeAddress);

View file

@ -0,0 +1,62 @@
//
// PacketHeaders.cpp
// hifi
//
// Created by Stephen Birarda on 6/28/13.
// Copyright (c) 2013 HighFidelity, Inc. All rights reserved.
//
#include <stdio.h>
#include "PacketHeaders.h"
PACKET_VERSION versionForPacketType(PACKET_TYPE type) {
switch (type) {
default:
return 0;
break;
}
}
bool packetVersionMatch(unsigned char* packetHeader) {
// currently this just checks if the version in the packet matches our return from versionForPacketType
// may need to be expanded in the future for types and versions that take > than 1 byte
if (packetHeader[1] == versionForPacketType(packetHeader[0])) {
return true;
} else {
printf("There is a packet version mismatch for packet with header %c\n", packetHeader[0]);
return false;
}
}
int populateTypeAndVersion(unsigned char* destinationHeader, PACKET_TYPE type) {
destinationHeader[0] = type;
destinationHeader[1] = versionForPacketType(type);
// return the number of bytes written for pointer pushing
return 2;
}
int numBytesForPacketType(const unsigned char* packetType) {
if (packetType[0] == 255) {
return 1 + numBytesForPacketType(packetType + 1);
} else {
return 1;
}
}
int numBytesForPacketVersion(const unsigned char* packetVersion) {
if (packetVersion[0] == 255) {
return 1 + numBytesForPacketVersion(packetVersion + 1);
} else {
return 1;
}
}
int numBytesForPacketHeader(unsigned char* packetHeader) {
// int numBytesType = numBytesForPacketType(packetHeader);
// return numBytesType + numBytesForPacketVersion(packetHeader + numBytesType);
// currently this need not be dynamic - there are 2 bytes for each packet header
return 2;
}

View file

@ -12,28 +12,38 @@
#ifndef hifi_PacketHeaders_h #ifndef hifi_PacketHeaders_h
#define hifi_PacketHeaders_h #define hifi_PacketHeaders_h
typedef char PACKET_HEADER; typedef char PACKET_TYPE;
const PACKET_HEADER PACKET_HEADER_DOMAIN = 'D'; const PACKET_TYPE PACKET_TYPE_DOMAIN = 'D';
const PACKET_HEADER PACKET_HEADER_PING = 'P'; const PACKET_TYPE PACKET_TYPE_PING = 'P';
const PACKET_HEADER PACKET_HEADER_PING_REPLY = 'R'; const PACKET_TYPE PACKET_TYPE_PING_REPLY = 'R';
const PACKET_HEADER PACKET_HEADER_HEAD_DATA = 'H'; const PACKET_TYPE PACKET_TYPE_HEAD_DATA = 'H';
const PACKET_HEADER PACKET_HEADER_Z_COMMAND = 'Z'; const PACKET_TYPE PACKET_TYPE_Z_COMMAND = 'Z';
const PACKET_HEADER PACKET_HEADER_INJECT_AUDIO = 'I'; const PACKET_TYPE PACKET_TYPE_INJECT_AUDIO = 'I';
const PACKET_HEADER PACKET_HEADER_MIXED_AUDIO = 'A'; const PACKET_TYPE PACKET_TYPE_MIXED_AUDIO = 'A';
const PACKET_HEADER PACKET_HEADER_MICROPHONE_AUDIO_NO_ECHO = 'M'; const PACKET_TYPE PACKET_TYPE_MICROPHONE_AUDIO_NO_ECHO = 'M';
const PACKET_HEADER PACKET_HEADER_MICROPHONE_AUDIO_WITH_ECHO = 'm'; const PACKET_TYPE PACKET_TYPE_MICROPHONE_AUDIO_WITH_ECHO = 'm';
const PACKET_HEADER PACKET_HEADER_SET_VOXEL = 'S'; const PACKET_TYPE PACKET_TYPE_SET_VOXEL = 'S';
const PACKET_HEADER PACKET_HEADER_SET_VOXEL_DESTRUCTIVE = 'O'; const PACKET_TYPE PACKET_TYPE_SET_VOXEL_DESTRUCTIVE = 'O';
const PACKET_HEADER PACKET_HEADER_ERASE_VOXEL = 'E'; const PACKET_TYPE PACKET_TYPE_ERASE_VOXEL = 'E';
const PACKET_HEADER PACKET_HEADER_VOXEL_DATA = 'V'; const PACKET_TYPE PACKET_TYPE_VOXEL_DATA = 'V';
const PACKET_HEADER PACKET_HEADER_VOXEL_DATA_MONOCHROME = 'v'; const PACKET_TYPE PACKET_TYPE_VOXEL_DATA_MONOCHROME = 'v';
const PACKET_HEADER PACKET_HEADER_BULK_AVATAR_DATA = 'X'; const PACKET_TYPE PACKET_TYPE_BULK_AVATAR_DATA = 'X';
const PACKET_HEADER PACKET_HEADER_AVATAR_VOXEL_URL = 'U'; const PACKET_TYPE PACKET_TYPE_AVATAR_VOXEL_URL = 'U';
const PACKET_HEADER PACKET_HEADER_TRANSMITTER_DATA_V2 = 'T'; const PACKET_TYPE PACKET_TYPE_TRANSMITTER_DATA_V2 = 'T';
const PACKET_HEADER PACKET_HEADER_ENVIRONMENT_DATA = 'e'; const PACKET_TYPE PACKET_TYPE_ENVIRONMENT_DATA = 'e';
const PACKET_HEADER PACKET_HEADER_DOMAIN_LIST_REQUEST = 'L'; const PACKET_TYPE PACKET_TYPE_DOMAIN_LIST_REQUEST = 'L';
const PACKET_HEADER PACKET_HEADER_DOMAIN_REPORT_FOR_DUTY = 'C'; const PACKET_TYPE PACKET_TYPE_DOMAIN_REPORT_FOR_DUTY = 'C';
typedef char PACKET_VERSION;
PACKET_VERSION versionForPacketType(PACKET_TYPE type);
bool packetVersionMatch(unsigned char* packetHeader);
int populateTypeAndVersion(unsigned char* destinationHeader, PACKET_TYPE type);
int numBytesForPacketHeader(unsigned char* packetHeader);
const int MAX_PACKET_HEADER_BYTES = sizeof(PACKET_TYPE) + sizeof(PACKET_VERSION);
// These are supported Z-Command // These are supported Z-Command
#define ERASE_ALL_COMMAND "erase all" #define ERASE_ALL_COMMAND "erase all"

View file

@ -11,17 +11,20 @@
#include <cstring> #include <cstring>
#include <cctype> #include <cctype>
#include <time.h> #include <time.h>
#ifdef _WIN32 #ifdef _WIN32
#include "Syssocket.h" #include "Syssocket.h"
#endif #endif
#include "Log.h"
#include "SharedUtil.h"
#include "OctalCode.h"
#ifdef __APPLE__ #ifdef __APPLE__
#include <CoreFoundation/CoreFoundation.h> #include <CoreFoundation/CoreFoundation.h>
#endif #endif
#include "Log.h"
#include "OctalCode.h"
#include "PacketHeaders.h"
#include "SharedUtil.h"
uint64_t usecTimestamp(timeval *time) { uint64_t usecTimestamp(timeval *time) {
return (time->tv_sec * 1000000 + time->tv_usec); return (time->tv_sec * 1000000 + time->tv_usec);
} }
@ -209,13 +212,14 @@ bool createVoxelEditMessage(unsigned char command, short int sequence,
int messageSize = MAXIMUM_EDIT_VOXEL_MESSAGE_SIZE; // just a guess for now int messageSize = MAXIMUM_EDIT_VOXEL_MESSAGE_SIZE; // just a guess for now
int actualMessageSize = 3; int actualMessageSize = 3;
unsigned char* messageBuffer = new unsigned char[messageSize]; unsigned char* messageBuffer = new unsigned char[messageSize];
unsigned short int* sequenceAt = (unsigned short int*)&messageBuffer[1];
messageBuffer[0]=command; int numBytesPacketHeader = populateTypeAndVersion(messageBuffer, command);
*sequenceAt=sequence; unsigned short int* sequenceAt = (unsigned short int*) &messageBuffer[numBytesPacketHeader];
unsigned char* copyAt = &messageBuffer[3];
for (int i=0;i<voxelCount && success;i++) { *sequenceAt = sequence;
unsigned char* copyAt = &messageBuffer[numBytesPacketHeader + sizeof(sequence)];
for (int i = 0; i < voxelCount && success; i++) {
// get the coded voxel // get the coded voxel
unsigned char* voxelData = pointToVoxel(voxelDetails[i].x,voxelDetails[i].y,voxelDetails[i].z, unsigned char* voxelData = pointToVoxel(voxelDetails[i].x,voxelDetails[i].y,voxelDetails[i].z,
voxelDetails[i].s,voxelDetails[i].red,voxelDetails[i].green,voxelDetails[i].blue); voxelDetails[i].s,voxelDetails[i].red,voxelDetails[i].green,voxelDetails[i].blue);
@ -224,12 +228,12 @@ bool createVoxelEditMessage(unsigned char command, short int sequence,
// make sure we have room to copy this voxel // make sure we have room to copy this voxel
if (actualMessageSize+lengthOfVoxelData > MAXIMUM_EDIT_VOXEL_MESSAGE_SIZE) { if (actualMessageSize+lengthOfVoxelData > MAXIMUM_EDIT_VOXEL_MESSAGE_SIZE) {
success=false; success = false;
} else { } else {
// add it to our message // add it to our message
memcpy(copyAt,voxelData,lengthOfVoxelData); memcpy(copyAt, voxelData, lengthOfVoxelData);
copyAt+=lengthOfVoxelData; copyAt += lengthOfVoxelData;
actualMessageSize+=lengthOfVoxelData; actualMessageSize += lengthOfVoxelData;
} }
// cleanup // cleanup
delete[] voxelData; delete[] voxelData;
@ -238,9 +242,10 @@ bool createVoxelEditMessage(unsigned char command, short int sequence,
if (success) { if (success) {
// finally, copy the result to the output // finally, copy the result to the output
bufferOut = new unsigned char[actualMessageSize]; bufferOut = new unsigned char[actualMessageSize];
sizeOut=actualMessageSize; sizeOut = actualMessageSize;
memcpy(bufferOut,messageBuffer,actualMessageSize); memcpy(bufferOut, messageBuffer, actualMessageSize);
} }
delete[] messageBuffer; // clean up our temporary buffer delete[] messageBuffer; // clean up our temporary buffer
return success; return success;
} }

View file

@ -596,7 +596,7 @@ void VoxelTree::readCodeColorBufferToTreeRecursion(VoxelNode* node, void* extraD
void VoxelTree::processRemoveVoxelBitstream(unsigned char * bitstream, int bufferSizeBytes) { void VoxelTree::processRemoveVoxelBitstream(unsigned char * bitstream, int bufferSizeBytes) {
//unsigned short int itemNumber = (*((unsigned short int*)&bitstream[sizeof(PACKET_HEADER)])); //unsigned short int itemNumber = (*((unsigned short int*)&bitstream[sizeof(PACKET_HEADER)]));
int atByte = sizeof(short int) + sizeof(PACKET_HEADER); int atByte = sizeof(short int) + numBytesForPacketHeader(bitstream);
unsigned char* voxelCode = (unsigned char*)&bitstream[atByte]; unsigned char* voxelCode = (unsigned char*)&bitstream[atByte];
while (atByte < bufferSizeBytes) { while (atByte < bufferSizeBytes) {
int codeLength = numberOfThreeBitSectionsInCode(voxelCode); int codeLength = numberOfThreeBitSectionsInCode(voxelCode);
@ -1169,7 +1169,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char* outp
// caller can pass NULL as viewFrustum if they want everything // caller can pass NULL as viewFrustum if they want everything
if (params.viewFrustum) { if (params.viewFrustum) {
float distance = node->distanceToCamera(*params.viewFrustum); float distance = node->distanceToCamera(*params.viewFrustum);
float boundaryDistance = boundaryDistanceForRenderLevel(*node->getOctalCode() + 1); float boundaryDistance = boundaryDistanceForRenderLevel(node->getLevel() + params.boundaryLevelAdjust);
// If we're too far away for our render level, then just return // If we're too far away for our render level, then just return
if (distance >= boundaryDistance) { if (distance >= boundaryDistance) {
@ -1183,6 +1183,25 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char* outp
return bytesAtThisLevel; return bytesAtThisLevel;
} }
// Ok, we are in view, but if we're in delta mode, then we also want to make sure we weren't already in view
// because we don't send nodes from the previously know in view frustum.
bool wasInView = false;
if (params.deltaViewFrustum && params.lastViewFrustum) {
ViewFrustum::location location = node->inFrustum(*params.lastViewFrustum);
// If we're a leaf, then either intersect or inside is considered "formerly in view"
if (node->isLeaf()) {
wasInView = location != ViewFrustum::OUTSIDE;
} else {
wasInView = location == ViewFrustum::INSIDE;
}
}
// If we were in view, then bail out early!
if (wasInView) {
return bytesAtThisLevel;
}
// If the user also asked for occlusion culling, check if this node is occluded, but only if it's not a leaf. // If the user also asked for occlusion culling, check if this node is occluded, but only if it's not a leaf.
// leaf occlusion is handled down below when we check child nodes // leaf occlusion is handled down below when we check child nodes
@ -1200,16 +1219,9 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char* outp
CoverageMapStorageResult result = params.map->checkMap(voxelPolygon, false); CoverageMapStorageResult result = params.map->checkMap(voxelPolygon, false);
delete voxelPolygon; // cleanup delete voxelPolygon; // cleanup
if (result == OCCLUDED) { if (result == OCCLUDED) {
//node->printDebugDetails("upper section, non-Leaf is occluded!! node=");
//args->nonLeavesOccluded++;
//args->subtreeVoxelsSkipped += (subArgs.voxelsTouched - 1);
//args->totalVoxels += (subArgs.voxelsTouched - 1);
return bytesAtThisLevel; return bytesAtThisLevel;
} }
} else { } else {
//node->printDebugDetails("upper section, shadow Not in view node=");
// If this shadow wasn't "all in view" then we ignored it for occlusion culling, but // If this shadow wasn't "all in view" then we ignored it for occlusion culling, but
// we do need to clean up memory and proceed as normal... // we do need to clean up memory and proceed as normal...
delete voxelPolygon; delete voxelPolygon;
@ -1285,7 +1297,8 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char* outp
if (childIsInView) { if (childIsInView) {
// Before we determine consider this further, let's see if it's in our LOD scope... // Before we determine consider this further, let's see if it's in our LOD scope...
float distance = distancesToChildren[i]; // params.viewFrustum ? childNode->distanceToCamera(*params.viewFrustum) : 0; float distance = distancesToChildren[i]; // params.viewFrustum ? childNode->distanceToCamera(*params.viewFrustum) : 0;
float boundaryDistance = params.viewFrustum ? boundaryDistanceForRenderLevel(*childNode->getOctalCode() + 1) : 1; float boundaryDistance = !params.viewFrustum ? 1 :
boundaryDistanceForRenderLevel(childNode->getLevel() + params.boundaryLevelAdjust);
if (distance < boundaryDistance) { if (distance < boundaryDistance) {
inViewCount++; inViewCount++;
@ -1341,7 +1354,8 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char* outp
if (params.viewFrustum && childNode->isColored() && !childNode->isLeaf()) { if (params.viewFrustum && childNode->isColored() && !childNode->isLeaf()) {
int grandChildrenInView = 0; int grandChildrenInView = 0;
int grandChildrenInLOD = 0; int grandChildrenInLOD = 0;
float grandChildBoundaryDistance = boundaryDistanceForRenderLevel(childNode->getLevel() + 2); float grandChildBoundaryDistance = boundaryDistanceForRenderLevel(childNode->getLevel() +
1 + params.boundaryLevelAdjust);
for (int grandChildIndex = 0; grandChildIndex < NUMBER_OF_CHILDREN; grandChildIndex++) { for (int grandChildIndex = 0; grandChildIndex < NUMBER_OF_CHILDREN; grandChildIndex++) {
VoxelNode* grandChild = childNode->getChildAtIndex(grandChildIndex); VoxelNode* grandChild = childNode->getChildAtIndex(grandChildIndex);

View file

@ -33,6 +33,8 @@ typedef enum {GRADIENT, RANDOM, NATURAL} creationMode;
#define WANT_OCCLUSION_CULLING true #define WANT_OCCLUSION_CULLING true
#define IGNORE_COVERAGE_MAP NULL #define IGNORE_COVERAGE_MAP NULL
#define DONT_CHOP 0 #define DONT_CHOP 0
#define NO_BOUNDARY_ADJUST 0
#define LOW_RES_MOVING_ADJUST 1
class EncodeBitstreamParams { class EncodeBitstreamParams {
public: public:
@ -46,6 +48,7 @@ public:
const ViewFrustum* lastViewFrustum; const ViewFrustum* lastViewFrustum;
bool wantOcclusionCulling; bool wantOcclusionCulling;
long childWasInViewDiscarded; long childWasInViewDiscarded;
int boundaryLevelAdjust;
CoverageMap* map; CoverageMap* map;
@ -58,18 +61,20 @@ public:
bool deltaViewFrustum = false, bool deltaViewFrustum = false,
const ViewFrustum* lastViewFrustum = IGNORE_VIEW_FRUSTUM, const ViewFrustum* lastViewFrustum = IGNORE_VIEW_FRUSTUM,
bool wantOcclusionCulling= NO_OCCLUSION_CULLING, bool wantOcclusionCulling= NO_OCCLUSION_CULLING,
CoverageMap* map = IGNORE_COVERAGE_MAP) : CoverageMap* map = IGNORE_COVERAGE_MAP,
maxEncodeLevel (maxEncodeLevel), int boundaryLevelAdjust = NO_BOUNDARY_ADJUST) :
maxLevelReached (0), maxEncodeLevel (maxEncodeLevel),
viewFrustum (viewFrustum), maxLevelReached (0),
includeColor (includeColor), viewFrustum (viewFrustum),
includeExistsBits (includeExistsBits), includeColor (includeColor),
chopLevels (chopLevels), includeExistsBits (includeExistsBits),
deltaViewFrustum (deltaViewFrustum), chopLevels (chopLevels),
lastViewFrustum (lastViewFrustum), deltaViewFrustum (deltaViewFrustum),
wantOcclusionCulling(wantOcclusionCulling), lastViewFrustum (lastViewFrustum),
childWasInViewDiscarded(0), wantOcclusionCulling (wantOcclusionCulling),
map (map) childWasInViewDiscarded (0),
boundaryLevelAdjust (boundaryLevelAdjust),
map (map)
{} {}
}; };

View file

@ -17,7 +17,9 @@ VoxelNodeData::VoxelNodeData(Node* owningNode) :
_voxelPacketAvailableBytes(MAX_VOXEL_PACKET_SIZE), _voxelPacketAvailableBytes(MAX_VOXEL_PACKET_SIZE),
_maxSearchLevel(1), _maxSearchLevel(1),
_maxLevelReachedInLastSearch(1), _maxLevelReachedInLastSearch(1),
_lastTimeBagEmpty(0) _lastTimeBagEmpty(0),
_viewFrustumChanging(false),
_currentPacketIsColor(true)
{ {
_voxelPacket = new unsigned char[MAX_VOXEL_PACKET_SIZE]; _voxelPacket = new unsigned char[MAX_VOXEL_PACKET_SIZE];
_voxelPacketAt = _voxelPacket; _voxelPacketAt = _voxelPacket;
@ -27,9 +29,13 @@ VoxelNodeData::VoxelNodeData(Node* owningNode) :
void VoxelNodeData::resetVoxelPacket() { void VoxelNodeData::resetVoxelPacket() {
_voxelPacket[0] = getWantColor() ? PACKET_HEADER_VOXEL_DATA : PACKET_HEADER_VOXEL_DATA_MONOCHROME; // If we're moving, and the client asked for low res, then we force monochrome, otherwise, use
_voxelPacketAt = &_voxelPacket[1]; // the clients requested color state.
_voxelPacketAvailableBytes = MAX_VOXEL_PACKET_SIZE - 1; _currentPacketIsColor = (getWantLowResMoving() && _viewFrustumChanging) ? false : getWantColor();
PACKET_TYPE voxelPacketType = _currentPacketIsColor ? PACKET_TYPE_VOXEL_DATA : PACKET_TYPE_VOXEL_DATA_MONOCHROME;
int numBytesPacketHeader = populateTypeAndVersion(_voxelPacket, voxelPacketType);
_voxelPacketAt = _voxelPacket + numBytesPacketHeader;
_voxelPacketAvailableBytes = MAX_VOXEL_PACKET_SIZE - numBytesPacketHeader;
_voxelPacketWaiting = false; _voxelPacketWaiting = false;
} }
@ -63,6 +69,7 @@ bool VoxelNodeData::updateCurrentViewFrustum() {
_currentViewFrustum.calculate(); _currentViewFrustum.calculate();
currentViewFrustumChanged = true; currentViewFrustumChanged = true;
} }
_viewFrustumChanging = currentViewFrustumChanged;
return currentViewFrustumChanged; return currentViewFrustumChanged;
} }

View file

@ -53,6 +53,7 @@ public:
uint64_t getLastTimeBagEmpty() const { return _lastTimeBagEmpty; }; uint64_t getLastTimeBagEmpty() const { return _lastTimeBagEmpty; };
void setLastTimeBagEmpty(uint64_t lastTimeBagEmpty) { _lastTimeBagEmpty = lastTimeBagEmpty; }; void setLastTimeBagEmpty(uint64_t lastTimeBagEmpty) { _lastTimeBagEmpty = lastTimeBagEmpty; };
bool getCurrentPacketIsColor() const { return _currentPacketIsColor; };
private: private:
VoxelNodeData(const VoxelNodeData &); VoxelNodeData(const VoxelNodeData &);
VoxelNodeData& operator= (const VoxelNodeData&); VoxelNodeData& operator= (const VoxelNodeData&);
@ -67,7 +68,8 @@ private:
ViewFrustum _currentViewFrustum; ViewFrustum _currentViewFrustum;
ViewFrustum _lastKnownViewFrustum; ViewFrustum _lastKnownViewFrustum;
uint64_t _lastTimeBagEmpty; uint64_t _lastTimeBagEmpty;
bool _viewFrustumChanging;
bool _currentPacketIsColor;
}; };
#endif /* defined(__hifi__VoxelNodeData__) */ #endif /* defined(__hifi__VoxelNodeData__) */

View file

@ -2,7 +2,7 @@
// main.cpp // main.cpp
// Voxel Server // Voxel Server
// //
// Created by Stephen Birara on 03/06/13. // Created by Stephen Birarda on 03/06/13.
// Copyright (c) 2012 High Fidelity, Inc. All rights reserved. // Copyright (c) 2012 High Fidelity, Inc. All rights reserved.
// //
@ -123,9 +123,47 @@ void deepestLevelVoxelDistributor(NodeList* nodeList,
int maxLevelReached = 0; int maxLevelReached = 0;
uint64_t start = usecTimestampNow(); uint64_t start = usecTimestampNow();
int truePacketsSent = 0;
int trueBytesSent = 0;
// FOR NOW... node tells us if it wants to receive only view frustum deltas // FOR NOW... node tells us if it wants to receive only view frustum deltas
bool wantDelta = viewFrustumChanged && nodeData->getWantDelta(); bool wantDelta = viewFrustumChanged && nodeData->getWantDelta();
// If our packet already has content in it, then we must use the color choice of the waiting packet.
// If we're starting a fresh packet, then...
// If we're moving, and the client asked for low res, then we force monochrome, otherwise, use
// the clients requested color state.
bool wantColor = ((nodeData->getWantLowResMoving() && viewFrustumChanged) ? false : nodeData->getWantColor());
// If we have a packet waiting, and our desired want color, doesn't match the current waiting packets color
// then let's just send that waiting packet.
if (wantColor != nodeData->getCurrentPacketIsColor()) {
if (nodeData->isPacketWaiting()) {
if (::debugVoxelSending) {
printf("wantColor=%s --- SENDING PARTIAL PACKET! nodeData->getCurrentPacketIsColor()=%s\n",
debug::valueOf(wantColor), debug::valueOf(nodeData->getCurrentPacketIsColor()));
}
nodeList->getNodeSocket()->send(node->getActiveSocket(),
nodeData->getPacket(), nodeData->getPacketLength());
trueBytesSent += nodeData->getPacketLength();
truePacketsSent++;
nodeData->resetVoxelPacket();
} else {
if (::debugVoxelSending) {
printf("wantColor=%s --- FIXING HEADER! nodeData->getCurrentPacketIsColor()=%s\n",
debug::valueOf(wantColor), debug::valueOf(nodeData->getCurrentPacketIsColor()));
}
nodeData->resetVoxelPacket();
}
}
if (::debugVoxelSending) {
printf("wantColor=%s getCurrentPacketIsColor()=%s, viewFrustumChanged=%s, getWantLowResMoving()=%s\n",
debug::valueOf(wantColor), debug::valueOf(nodeData->getCurrentPacketIsColor()),
debug::valueOf(viewFrustumChanged), debug::valueOf(nodeData->getWantLowResMoving()));
}
const ViewFrustum* lastViewFrustum = wantDelta ? &nodeData->getLastKnownViewFrustum() : NULL; const ViewFrustum* lastViewFrustum = wantDelta ? &nodeData->getLastKnownViewFrustum() : NULL;
if (::debugVoxelSending) { if (::debugVoxelSending) {
@ -149,9 +187,11 @@ void deepestLevelVoxelDistributor(NodeList* nodeList,
} else { } else {
printf("elapsed time to send scene = %f seconds", elapsedSceneSend); printf("elapsed time to send scene = %f seconds", elapsedSceneSend);
} }
printf(" [occlusionCulling: %s]\n", debug::valueOf(nodeData->getWantOcclusionCulling())); printf(" [occlusionCulling:%s, wantDelta:%s, wantColor:%s ]\n",
debug::valueOf(nodeData->getWantOcclusionCulling()), debug::valueOf(wantDelta),
debug::valueOf(wantColor));
} }
nodeData->setLastTimeBagEmpty(now); nodeData->setLastTimeBagEmpty(now); // huh? why is this inside debug? probably not what we want
} }
// if our view has changed, we need to reset these things... // if our view has changed, we need to reset these things...
@ -199,8 +239,6 @@ void deepestLevelVoxelDistributor(NodeList* nodeList,
static unsigned char tempOutputBuffer[MAX_VOXEL_PACKET_SIZE - 1]; // save on allocs by making this static static unsigned char tempOutputBuffer[MAX_VOXEL_PACKET_SIZE - 1]; // save on allocs by making this static
int bytesWritten = 0; int bytesWritten = 0;
int packetsSentThisInterval = 0; int packetsSentThisInterval = 0;
int truePacketsSent = 0;
int trueBytesSent = 0;
uint64_t start = usecTimestampNow(); uint64_t start = usecTimestampNow();
bool shouldSendEnvironments = shouldDo(ENVIRONMENT_SEND_INTERVAL_USECS, VOXEL_SEND_INTERVAL_USECS); bool shouldSendEnvironments = shouldDo(ENVIRONMENT_SEND_INTERVAL_USECS, VOXEL_SEND_INTERVAL_USECS);
@ -224,10 +262,12 @@ void deepestLevelVoxelDistributor(NodeList* nodeList,
VoxelNode* subTree = nodeData->nodeBag.extract(); VoxelNode* subTree = nodeData->nodeBag.extract();
bool wantOcclusionCulling = nodeData->getWantOcclusionCulling(); bool wantOcclusionCulling = nodeData->getWantOcclusionCulling();
CoverageMap* coverageMap = wantOcclusionCulling ? &nodeData->map : IGNORE_COVERAGE_MAP; CoverageMap* coverageMap = wantOcclusionCulling ? &nodeData->map : IGNORE_COVERAGE_MAP;
int boundaryLevelAdjust = viewFrustumChanged && nodeData->getWantLowResMoving()
? LOW_RES_MOVING_ADJUST : NO_BOUNDARY_ADJUST;
EncodeBitstreamParams params(INT_MAX, &nodeData->getCurrentViewFrustum(), nodeData->getWantColor(), EncodeBitstreamParams params(INT_MAX, &nodeData->getCurrentViewFrustum(), wantColor,
WANT_EXISTS_BITS, DONT_CHOP, wantDelta, lastViewFrustum, WANT_EXISTS_BITS, DONT_CHOP, wantDelta, lastViewFrustum,
wantOcclusionCulling, coverageMap); wantOcclusionCulling, coverageMap, boundaryLevelAdjust);
bytesWritten = serverTree.encodeTreeBitstream(subTree, &tempOutputBuffer[0], MAX_VOXEL_PACKET_SIZE - 1, bytesWritten = serverTree.encodeTreeBitstream(subTree, &tempOutputBuffer[0], MAX_VOXEL_PACKET_SIZE - 1,
nodeData->nodeBag, params); nodeData->nodeBag, params);
@ -254,18 +294,19 @@ void deepestLevelVoxelDistributor(NodeList* nodeList,
trueBytesSent += nodeData->getPacketLength(); trueBytesSent += nodeData->getPacketLength();
truePacketsSent++; truePacketsSent++;
nodeData->resetVoxelPacket(); nodeData->resetVoxelPacket();
} }
packetsSentThisInterval = PACKETS_PER_CLIENT_PER_INTERVAL; // done for now, no nodes left packetsSentThisInterval = PACKETS_PER_CLIENT_PER_INTERVAL; // done for now, no nodes left
} }
} }
// send the environment packet // send the environment packet
if (shouldSendEnvironments) { if (shouldSendEnvironments) {
int envPacketLength = 1; int numBytesPacketHeader = populateTypeAndVersion(tempOutputBuffer, PACKET_TYPE_ENVIRONMENT_DATA);
*tempOutputBuffer = PACKET_HEADER_ENVIRONMENT_DATA; int envPacketLength = numBytesPacketHeader;
for (int i = 0; i < sizeof(environmentData) / sizeof(environmentData[0]); i++) {
for (int i = 0; i < sizeof(environmentData) / sizeof(EnvironmentData); i++) {
envPacketLength += environmentData[i].getBroadcastData(tempOutputBuffer + envPacketLength); envPacketLength += environmentData[i].getBroadcastData(tempOutputBuffer + envPacketLength);
} }
nodeList->getNodeSocket()->send(node->getActiveSocket(), tempOutputBuffer, envPacketLength); nodeList->getNodeSocket()->send(node->getActiveSocket(), tempOutputBuffer, envPacketLength);
trueBytesSent += envPacketLength; trueBytesSent += envPacketLength;
truePacketsSent++; truePacketsSent++;
@ -509,19 +550,24 @@ int main(int argc, const char * argv[]) {
// check to see if we need to persist our voxel state // check to see if we need to persist our voxel state
persistVoxelsWhenDirty(); persistVoxelsWhenDirty();
if (nodeList->getNodeSocket()->receive(&nodePublicAddress, packetData, &receivedBytes)) { if (nodeList->getNodeSocket()->receive(&nodePublicAddress, packetData, &receivedBytes) &&
if (packetData[0] == PACKET_HEADER_SET_VOXEL || packetData[0] == PACKET_HEADER_SET_VOXEL_DESTRUCTIVE) { packetVersionMatch(packetData)) {
bool destructive = (packetData[0] == PACKET_HEADER_SET_VOXEL_DESTRUCTIVE);
int numBytesPacketHeader = numBytesForPacketHeader(packetData);
if (packetData[0] == PACKET_TYPE_SET_VOXEL || packetData[0] == PACKET_TYPE_SET_VOXEL_DESTRUCTIVE) {
bool destructive = (packetData[0] == PACKET_TYPE_SET_VOXEL_DESTRUCTIVE);
PerformanceWarning warn(::shouldShowAnimationDebug, PerformanceWarning warn(::shouldShowAnimationDebug,
destructive ? "PACKET_HEADER_SET_VOXEL_DESTRUCTIVE" : "PACKET_HEADER_SET_VOXEL", destructive ? "PACKET_TYPE_SET_VOXEL_DESTRUCTIVE" : "PACKET_TYPE_SET_VOXEL",
::shouldShowAnimationDebug); ::shouldShowAnimationDebug);
unsigned short int itemNumber = (*((unsigned short int*)&packetData[1]));
unsigned short int itemNumber = (*((unsigned short int*)(packetData + numBytesPacketHeader)));
if (::shouldShowAnimationDebug) { if (::shouldShowAnimationDebug) {
printf("got %s - command from client receivedBytes=%ld itemNumber=%d\n", printf("got %s - command from client receivedBytes=%ld itemNumber=%d\n",
destructive ? "PACKET_HEADER_SET_VOXEL_DESTRUCTIVE" : "PACKET_HEADER_SET_VOXEL", destructive ? "PACKET_TYPE_SET_VOXEL_DESTRUCTIVE" : "PACKET_TYPE_SET_VOXEL",
receivedBytes,itemNumber); receivedBytes,itemNumber);
} }
int atByte = sizeof(PACKET_HEADER) + sizeof(itemNumber); int atByte = numBytesPacketHeader + sizeof(itemNumber);
unsigned char* voxelData = (unsigned char*)&packetData[atByte]; unsigned char* voxelData = (unsigned char*)&packetData[atByte];
while (atByte < receivedBytes) { while (atByte < receivedBytes) {
unsigned char octets = (unsigned char)*voxelData; unsigned char octets = (unsigned char)*voxelData;
@ -563,21 +609,20 @@ int main(int argc, const char * argv[]) {
voxelData += voxelDataSize; voxelData += voxelDataSize;
atByte += voxelDataSize; atByte += voxelDataSize;
} }
} } else if (packetData[0] == PACKET_TYPE_ERASE_VOXEL) {
if (packetData[0] == PACKET_HEADER_ERASE_VOXEL) {
// Send these bits off to the VoxelTree class to process them // Send these bits off to the VoxelTree class to process them
pthread_mutex_lock(&::treeLock); pthread_mutex_lock(&::treeLock);
serverTree.processRemoveVoxelBitstream((unsigned char*)packetData, receivedBytes); serverTree.processRemoveVoxelBitstream((unsigned char*)packetData, receivedBytes);
pthread_mutex_unlock(&::treeLock); pthread_mutex_unlock(&::treeLock);
} } else if (packetData[0] == PACKET_TYPE_Z_COMMAND) {
if (packetData[0] == PACKET_HEADER_Z_COMMAND) {
// the Z command is a special command that allows the sender to send the voxel server high level semantic // 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 // requests, like erase all, or add sphere scene
char* command = (char*) &packetData[1]; // start of the command
char* command = (char*) &packetData[numBytesPacketHeader]; // start of the command
int commandLength = strlen(command); // commands are null terminated strings int commandLength = strlen(command); // commands are null terminated strings
int totalLength = sizeof(PACKET_HEADER_Z_COMMAND) + commandLength + 1; // 1 for null termination int totalLength = numBytesPacketHeader + commandLength + 1; // 1 for null termination
printf("got Z message len(%ld)= %s\n", receivedBytes, command); printf("got Z message len(%ld)= %s\n", receivedBytes, command);
bool rebroadcast = true; // by default rebroadcast bool rebroadcast = true; // by default rebroadcast
@ -603,21 +648,20 @@ int main(int argc, const char * argv[]) {
printf("rebroadcasting Z message to connected nodes... nodeList.broadcastToNodes()\n"); printf("rebroadcasting Z message to connected nodes... nodeList.broadcastToNodes()\n");
nodeList->broadcastToNodes(packetData, receivedBytes, &NODE_TYPE_AGENT, 1); nodeList->broadcastToNodes(packetData, receivedBytes, &NODE_TYPE_AGENT, 1);
} }
} } else if (packetData[0] == PACKET_TYPE_HEAD_DATA) {
// If we got a PACKET_HEADER_HEAD_DATA, then we're talking to an NODE_TYPE_AVATAR, and we // If we got a PACKET_TYPE_HEAD_DATA, then we're talking to an NODE_TYPE_AVATAR, and we
// need to make sure we have it in our nodeList. // need to make sure we have it in our nodeList.
if (packetData[0] == PACKET_HEADER_HEAD_DATA) {
uint16_t nodeID = 0; uint16_t nodeID = 0;
unpackNodeId(packetData + sizeof(PACKET_HEADER_HEAD_DATA), &nodeID); unpackNodeId(packetData + numBytesPacketHeader, &nodeID);
Node* node = nodeList->addOrUpdateNode(&nodePublicAddress, Node* node = nodeList->addOrUpdateNode(&nodePublicAddress,
&nodePublicAddress, &nodePublicAddress,
NODE_TYPE_AGENT, NODE_TYPE_AGENT,
nodeID); nodeID);
nodeList->updateNodeWithData(node, packetData, receivedBytes); nodeList->updateNodeWithData(node, packetData, receivedBytes);
} } else if (packetData[0] == PACKET_TYPE_PING) {
// If the packet is a ping, let processNodeData handle it. // If the packet is a ping, let processNodeData handle it.
if (packetData[0] == PACKET_HEADER_PING) {
nodeList->processNodeData(&nodePublicAddress, packetData, receivedBytes); nodeList->processNodeData(&nodePublicAddress, packetData, receivedBytes);
} }
} }