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,9 +347,10 @@ 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,
@ -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++) {
@ -392,7 +394,7 @@ int main(int argc, const char* argv[]) {
// 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;
@ -116,10 +120,10 @@ int main(int argc, const char * argv[])
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);
} }
@ -173,7 +177,7 @@ 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,37 +3183,40 @@ void* Application::networkReceive(void* args) {
app->_packetCount++; app->_packetCount++;
app->_bytesCount += bytesReceived; app->_bytesCount += bytesReceived;
if (packetVersionMatch(app->_incomingPacket)) {
// only process this packet if we have a match on the packet version
switch (app->_incomingPacket[0]) { switch (app->_incomingPacket[0]) {
case PACKET_HEADER_TRANSMITTER_DATA_V2: case PACKET_TYPE_TRANSMITTER_DATA_V2:
// V2 = IOS transmitter app // V2 = IOS transmitter app
app->_myTransmitter.processIncomingData(app->_incomingPacket, bytesReceived); 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,6 +113,7 @@ 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 (_wantLowResMoving) { setAtBit(bitItems, WANT_LOW_RES_MOVING_BIT); }
if (_wantColor) { setAtBit(bitItems, WANT_COLOR_AT_BIT); } if (_wantColor) { setAtBit(bitItems, WANT_COLOR_AT_BIT); }
if (_wantDelta) { setAtBit(bitItems, WANT_DELTA_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); }
@ -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,6 +241,7 @@ 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++;
_wantLowResMoving = oneAtBit(bitItems, WANT_LOW_RES_MOVING_BIT);
_wantColor = oneAtBit(bitItems, WANT_COLOR_AT_BIT); _wantColor = oneAtBit(bitItems, WANT_COLOR_AT_BIT);
_wantDelta = oneAtBit(bitItems, WANT_DELTA_AT_BIT); _wantDelta = oneAtBit(bitItems, WANT_DELTA_AT_BIT);
_wantOcclusionCulling = oneAtBit(bitItems, WANT_OCCLUSION_CULLING_BIT); _wantOcclusionCulling = oneAtBit(bitItems, WANT_OCCLUSION_CULLING_BIT);

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
@ -93,9 +93,12 @@ public:
// 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 setWantColor(bool wantColor) { _wantColor = wantColor; }
void setWantDelta(bool wantDelta) { _wantDelta = wantDelta; } 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,7 +80,9 @@ 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;
} }
@ -89,19 +90,19 @@ void NodeList::timePingReply(sockaddr *nodeAddress, unsigned char *packetData) {
} }
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);
@ -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()));
@ -281,7 +294,7 @@ 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)) {
@ -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,11 +212,12 @@ 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);
unsigned short int* sequenceAt = (unsigned short int*) &messageBuffer[numBytesPacketHeader];
*sequenceAt = sequence; *sequenceAt = sequence;
unsigned char* copyAt = &messageBuffer[3]; unsigned char* copyAt = &messageBuffer[numBytesPacketHeader + sizeof(sequence)];
for (int i = 0; i < voxelCount && success; i++) { for (int i = 0; i < voxelCount && success; i++) {
// get the coded voxel // get the coded voxel
@ -241,6 +245,7 @@ bool createVoxelEditMessage(unsigned char command, short int sequence,
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,7 +61,8 @@ 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,
int boundaryLevelAdjust = NO_BOUNDARY_ADJUST) :
maxEncodeLevel (maxEncodeLevel), maxEncodeLevel (maxEncodeLevel),
maxLevelReached (0), maxLevelReached (0),
viewFrustum (viewFrustum), viewFrustum (viewFrustum),
@ -69,6 +73,7 @@ public:
lastViewFrustum (lastViewFrustum), lastViewFrustum (lastViewFrustum),
wantOcclusionCulling (wantOcclusionCulling), wantOcclusionCulling (wantOcclusionCulling),
childWasInViewDiscarded (0), childWasInViewDiscarded (0),
boundaryLevelAdjust (boundaryLevelAdjust),
map (map) 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);
} }
} }