Merge branch 'master' of https://github.com/highfidelity/hifi into metavoxels

This commit is contained in:
Andrzej Kapolka 2014-06-18 18:08:19 -07:00
commit 2decfb9561
19 changed files with 306 additions and 238 deletions

View file

@ -33,7 +33,10 @@
#include <glm/gtx/vector_angle.hpp>
#include <QtCore/QCoreApplication>
#include <QtCore/QJsonArray>
#include <QtCore/QJsonDocument>
#include <QtCore/QJsonObject>
#include <QtCore/QJsonValue>
#include <QtCore/QTimer>
#include <Logging.h>
@ -71,11 +74,18 @@ AudioMixer::AudioMixer(const QByteArray& packet) :
_performanceThrottlingRatio(0.0f),
_numStatFrames(0),
_sumListeners(0),
_sumMixes(0)
_sumMixes(0),
_sourceUnattenuatedZone(NULL),
_listenerUnattenuatedZone(NULL)
{
}
AudioMixer::~AudioMixer() {
delete _sourceUnattenuatedZone;
delete _listenerUnattenuatedZone;
}
void AudioMixer::addBufferToMixForListeningNodeWithBuffer(PositionalAudioRingBuffer* bufferToAdd,
AvatarAudioRingBuffer* listeningNodeBuffer) {
float bearingRelativeAngleToSource = 0.0f;
@ -83,7 +93,9 @@ void AudioMixer::addBufferToMixForListeningNodeWithBuffer(PositionalAudioRingBuf
int numSamplesDelay = 0;
float weakChannelAmplitudeRatio = 1.0f;
if (bufferToAdd != listeningNodeBuffer) {
bool shouldAttenuate = (bufferToAdd != listeningNodeBuffer);
if (shouldAttenuate) {
// if the two buffer pointers do not match then these are different buffers
glm::vec3 relativePosition = bufferToAdd->getPosition() - listeningNodeBuffer->getPosition();
@ -101,82 +113,88 @@ void AudioMixer::addBufferToMixForListeningNodeWithBuffer(PositionalAudioRingBuf
++_sumMixes;
glm::quat inverseOrientation = glm::inverse(listeningNodeBuffer->getOrientation());
float distanceSquareToSource = glm::dot(relativePosition, relativePosition);
float radius = 0.0f;
if (bufferToAdd->getType() == PositionalAudioRingBuffer::Injector) {
InjectedAudioRingBuffer* injectedBuffer = (InjectedAudioRingBuffer*) bufferToAdd;
radius = injectedBuffer->getRadius();
attenuationCoefficient *= injectedBuffer->getAttenuationRatio();
if (bufferToAdd->getListenerUnattenuatedZone()) {
shouldAttenuate = !bufferToAdd->getListenerUnattenuatedZone()->contains(listeningNodeBuffer->getPosition());
}
if (radius == 0 || (distanceSquareToSource > radius * radius)) {
// this is either not a spherical source, or the listener is outside the sphere
if (radius > 0) {
// this is a spherical source - the distance used for the coefficient
// needs to be the closest point on the boundary to the source
// ovveride the distance to the node with the distance to the point on the
// boundary of the sphere
distanceSquareToSource -= (radius * radius);
} else {
// calculate the angle delivery for off-axis attenuation
glm::vec3 rotatedListenerPosition = glm::inverse(bufferToAdd->getOrientation()) * relativePosition;
float angleOfDelivery = glm::angle(glm::vec3(0.0f, 0.0f, -1.0f),
glm::normalize(rotatedListenerPosition));
const float MAX_OFF_AXIS_ATTENUATION = 0.2f;
const float OFF_AXIS_ATTENUATION_FORMULA_STEP = (1 - MAX_OFF_AXIS_ATTENUATION) / 2.0f;
float offAxisCoefficient = MAX_OFF_AXIS_ATTENUATION +
(OFF_AXIS_ATTENUATION_FORMULA_STEP * (angleOfDelivery / PI_OVER_TWO));
// multiply the current attenuation coefficient by the calculated off axis coefficient
attenuationCoefficient *= offAxisCoefficient;
if (shouldAttenuate) {
glm::quat inverseOrientation = glm::inverse(listeningNodeBuffer->getOrientation());
float distanceSquareToSource = glm::dot(relativePosition, relativePosition);
float radius = 0.0f;
if (bufferToAdd->getType() == PositionalAudioRingBuffer::Injector) {
InjectedAudioRingBuffer* injectedBuffer = (InjectedAudioRingBuffer*) bufferToAdd;
radius = injectedBuffer->getRadius();
attenuationCoefficient *= injectedBuffer->getAttenuationRatio();
}
if (radius == 0 || (distanceSquareToSource > radius * radius)) {
// this is either not a spherical source, or the listener is outside the sphere
if (radius > 0) {
// this is a spherical source - the distance used for the coefficient
// needs to be the closest point on the boundary to the source
// ovveride the distance to the node with the distance to the point on the
// boundary of the sphere
distanceSquareToSource -= (radius * radius);
} else {
// calculate the angle delivery for off-axis attenuation
glm::vec3 rotatedListenerPosition = glm::inverse(bufferToAdd->getOrientation()) * relativePosition;
float angleOfDelivery = glm::angle(glm::vec3(0.0f, 0.0f, -1.0f),
glm::normalize(rotatedListenerPosition));
const float MAX_OFF_AXIS_ATTENUATION = 0.2f;
const float OFF_AXIS_ATTENUATION_FORMULA_STEP = (1 - MAX_OFF_AXIS_ATTENUATION) / 2.0f;
float offAxisCoefficient = MAX_OFF_AXIS_ATTENUATION +
(OFF_AXIS_ATTENUATION_FORMULA_STEP * (angleOfDelivery / PI_OVER_TWO));
// multiply the current attenuation coefficient by the calculated off axis coefficient
attenuationCoefficient *= offAxisCoefficient;
}
glm::vec3 rotatedSourcePosition = inverseOrientation * relativePosition;
const float DISTANCE_SCALE = 2.5f;
const float GEOMETRIC_AMPLITUDE_SCALAR = 0.3f;
const float DISTANCE_LOG_BASE = 2.5f;
const float DISTANCE_SCALE_LOG = logf(DISTANCE_SCALE) / logf(DISTANCE_LOG_BASE);
// calculate the distance coefficient using the distance to this node
float distanceCoefficient = powf(GEOMETRIC_AMPLITUDE_SCALAR,
DISTANCE_SCALE_LOG +
(0.5f * logf(distanceSquareToSource) / logf(DISTANCE_LOG_BASE)) - 1);
distanceCoefficient = std::min(1.0f, distanceCoefficient);
// multiply the current attenuation coefficient by the distance coefficient
attenuationCoefficient *= distanceCoefficient;
// project the rotated source position vector onto the XZ plane
rotatedSourcePosition.y = 0.0f;
// produce an oriented angle about the y-axis
bearingRelativeAngleToSource = glm::orientedAngle(glm::vec3(0.0f, 0.0f, -1.0f),
glm::normalize(rotatedSourcePosition),
glm::vec3(0.0f, 1.0f, 0.0f));
const float PHASE_AMPLITUDE_RATIO_AT_90 = 0.5;
// figure out the number of samples of delay and the ratio of the amplitude
// in the weak channel for audio spatialization
float sinRatio = fabsf(sinf(bearingRelativeAngleToSource));
numSamplesDelay = SAMPLE_PHASE_DELAY_AT_90 * sinRatio;
weakChannelAmplitudeRatio = 1 - (PHASE_AMPLITUDE_RATIO_AT_90 * sinRatio);
}
glm::vec3 rotatedSourcePosition = inverseOrientation * relativePosition;
const float DISTANCE_SCALE = 2.5f;
const float GEOMETRIC_AMPLITUDE_SCALAR = 0.3f;
const float DISTANCE_LOG_BASE = 2.5f;
const float DISTANCE_SCALE_LOG = logf(DISTANCE_SCALE) / logf(DISTANCE_LOG_BASE);
// calculate the distance coefficient using the distance to this node
float distanceCoefficient = powf(GEOMETRIC_AMPLITUDE_SCALAR,
DISTANCE_SCALE_LOG +
(0.5f * logf(distanceSquareToSource) / logf(DISTANCE_LOG_BASE)) - 1);
distanceCoefficient = std::min(1.0f, distanceCoefficient);
// multiply the current attenuation coefficient by the distance coefficient
attenuationCoefficient *= distanceCoefficient;
// project the rotated source position vector onto the XZ plane
rotatedSourcePosition.y = 0.0f;
// produce an oriented angle about the y-axis
bearingRelativeAngleToSource = glm::orientedAngle(glm::vec3(0.0f, 0.0f, -1.0f),
glm::normalize(rotatedSourcePosition),
glm::vec3(0.0f, 1.0f, 0.0f));
const float PHASE_AMPLITUDE_RATIO_AT_90 = 0.5;
// figure out the number of samples of delay and the ratio of the amplitude
// in the weak channel for audio spatialization
float sinRatio = fabsf(sinf(bearingRelativeAngleToSource));
numSamplesDelay = SAMPLE_PHASE_DELAY_AT_90 * sinRatio;
weakChannelAmplitudeRatio = 1 - (PHASE_AMPLITUDE_RATIO_AT_90 * sinRatio);
}
}
const int16_t* nextOutputStart = bufferToAdd->getNextOutput();
if (!bufferToAdd->isStereo()) {
if (!bufferToAdd->isStereo() && shouldAttenuate) {
// this is a mono buffer, which means it gets full attenuation and spatialization
// if the bearing relative angle to source is > 0 then the delayed channel is the right one
@ -285,7 +303,8 @@ void AudioMixer::addBufferToMixForListeningNodeWithBuffer(PositionalAudioRingBuf
} else if (i + 1 < numSamplesDelay) {
// MMX add two delayed samples
__m64 bufferSamples = _mm_set_pi16(_clientSamples[parentIndex + delayedChannelOffset],
_clientSamples[parentIndex + SINGLE_STEREO_OFFSET + delayedChannelOffset], 0, 0);
_clientSamples[parentIndex + SINGLE_STEREO_OFFSET + delayedChannelOffset],
0, 0);
__m64 addSamples = _mm_set_pi16(delayNextOutputStart[i] * attenuationAndWeakChannelRatio,
delayNextOutputStart[i + 1] * attenuationAndWeakChannelRatio, 0, 0);
@ -307,16 +326,29 @@ void AudioMixer::addBufferToMixForListeningNodeWithBuffer(PositionalAudioRingBuf
}
}
} else {
// stereo buffer - do attenuation but no sample delay for spatialization
// this is a stereo buffer or an unattenuated buffer, don't perform spatialization
for (int s = 0; s < NETWORK_BUFFER_LENGTH_SAMPLES_STEREO; s += 4) {
// use MMX to clamp four additions at a time
_clientSamples[s] = glm::clamp(_clientSamples[s] + (int) (nextOutputStart[s] * attenuationCoefficient),
MIN_SAMPLE_VALUE, MAX_SAMPLE_VALUE);
_clientSamples[s + 1] = glm::clamp(_clientSamples[s + 1] + (int) (nextOutputStart[s + 1] * attenuationCoefficient),
int stereoDivider = bufferToAdd->isStereo() ? 1 : 2;
if (!shouldAttenuate) {
attenuationCoefficient = 1.0f;
}
_clientSamples[s] = glm::clamp(_clientSamples[s]
+ (int) (nextOutputStart[(s / stereoDivider)] * attenuationCoefficient),
MIN_SAMPLE_VALUE, MAX_SAMPLE_VALUE);
_clientSamples[s + 1] = glm::clamp(_clientSamples[s + 1]
+ (int) (nextOutputStart[(s / stereoDivider) + (1 / stereoDivider)]
* attenuationCoefficient),
MIN_SAMPLE_VALUE, MAX_SAMPLE_VALUE);
_clientSamples[s + 2] = glm::clamp(_clientSamples[s + 2] + (int) (nextOutputStart[s + 2] * attenuationCoefficient),
_clientSamples[s + 2] = glm::clamp(_clientSamples[s + 2]
+ (int) (nextOutputStart[(s / stereoDivider) + (2 / stereoDivider)]
* attenuationCoefficient),
MIN_SAMPLE_VALUE, MAX_SAMPLE_VALUE);
_clientSamples[s + 3] = glm::clamp(_clientSamples[s + 3] + (int) (nextOutputStart[s + 3] * attenuationCoefficient),
_clientSamples[s + 3] = glm::clamp(_clientSamples[s + 3]
+ (int) (nextOutputStart[(s / stereoDivider) + (3 / stereoDivider)]
* attenuationCoefficient),
MIN_SAMPLE_VALUE, MAX_SAMPLE_VALUE);
}
}
@ -412,6 +444,32 @@ void AudioMixer::run() {
nodeList->addNodeTypeToInterestSet(NodeType::Agent);
nodeList->linkedDataCreateCallback = attachNewBufferToNode;
// check the payload to see if we have any unattenuated zones
const QString UNATTENUATED_ZONE_REGEX_STRING = "--unattenuated-zone ([\\d.,-]+)";
QRegExp unattenuatedZoneMatch(UNATTENUATED_ZONE_REGEX_STRING);
if (unattenuatedZoneMatch.indexIn(_payload) != -1) {
QString unattenuatedZoneString = unattenuatedZoneMatch.cap(1);
QStringList zoneStringList = unattenuatedZoneString.split(',');
glm::vec3 sourceCorner(zoneStringList[0].toFloat(), zoneStringList[1].toFloat(), zoneStringList[2].toFloat());
glm::vec3 sourceDimensions(zoneStringList[3].toFloat(), zoneStringList[4].toFloat(), zoneStringList[5].toFloat());
glm::vec3 listenerCorner(zoneStringList[6].toFloat(), zoneStringList[7].toFloat(), zoneStringList[8].toFloat());
glm::vec3 listenerDimensions(zoneStringList[9].toFloat(), zoneStringList[10].toFloat(), zoneStringList[11].toFloat());
_sourceUnattenuatedZone = new AABox(sourceCorner, sourceDimensions);
_listenerUnattenuatedZone = new AABox(listenerCorner, listenerDimensions);
glm::vec3 sourceCenter = _sourceUnattenuatedZone->calcCenter();
glm::vec3 destinationCenter = _listenerUnattenuatedZone->calcCenter();
qDebug() << "There is an unattenuated zone with source center at"
<< QString("%1, %2, %3").arg(sourceCenter.x).arg(sourceCenter.y).arg(sourceCenter.z);
qDebug() << "Buffers inside this zone will not be attenuated inside a box with center at"
<< QString("%1, %2, %3").arg(destinationCenter.x).arg(destinationCenter.y).arg(destinationCenter.z);
}
int nextFrame = 0;
QElapsedTimer timer;
@ -429,7 +487,9 @@ void AudioMixer::run() {
foreach (const SharedNodePointer& node, nodeList->getNodeHash()) {
if (node->getLinkedData()) {
((AudioMixerClientData*) node->getLinkedData())->checkBuffersBeforeFrameSend(JITTER_BUFFER_SAMPLES);
((AudioMixerClientData*) node->getLinkedData())->checkBuffersBeforeFrameSend(JITTER_BUFFER_SAMPLES,
_sourceUnattenuatedZone,
_listenerUnattenuatedZone);
}
}

View file

@ -12,8 +12,8 @@
#ifndef hifi_AudioMixer_h
#define hifi_AudioMixer_h
#include <AABox.h>
#include <AudioRingBuffer.h>
#include <ThreadedAssignment.h>
class PositionalAudioRingBuffer;
@ -26,6 +26,7 @@ class AudioMixer : public ThreadedAssignment {
Q_OBJECT
public:
AudioMixer(const QByteArray& packet);
~AudioMixer();
public slots:
/// threaded run of assignment
void run();
@ -51,6 +52,8 @@ private:
int _numStatFrames;
int _sumListeners;
int _sumMixes;
AABox* _sourceUnattenuatedZone;
AABox* _listenerUnattenuatedZone;
};
#endif // hifi_AudioMixer_h

View file

@ -98,7 +98,8 @@ int AudioMixerClientData::parseData(const QByteArray& packet) {
return 0;
}
void AudioMixerClientData::checkBuffersBeforeFrameSend(int jitterBufferLengthSamples) {
void AudioMixerClientData::checkBuffersBeforeFrameSend(int jitterBufferLengthSamples,
AABox* checkSourceZone, AABox* listenerZone) {
for (int i = 0; i < _ringBuffers.size(); i++) {
if (_ringBuffers[i]->shouldBeAddedToMix(jitterBufferLengthSamples)) {
// this is a ring buffer that is ready to go
@ -108,6 +109,12 @@ void AudioMixerClientData::checkBuffersBeforeFrameSend(int jitterBufferLengthSam
// calculate the average loudness for the next NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL
// that would be mixed in
_ringBuffers[i]->updateNextOutputTrailingLoudness();
if (checkSourceZone && checkSourceZone->contains(_ringBuffers[i]->getPosition())) {
_ringBuffers[i]->setListenerUnattenuatedZone(listenerZone);
} else {
_ringBuffers[i]->setListenerUnattenuatedZone(NULL);
}
}
}
}

View file

@ -12,8 +12,7 @@
#ifndef hifi_AudioMixerClientData_h
#define hifi_AudioMixerClientData_h
#include <vector>
#include <AABox.h>
#include <NodeData.h>
#include <PositionalAudioRingBuffer.h>
@ -28,7 +27,8 @@ public:
AvatarAudioRingBuffer* getAvatarAudioRingBuffer() const;
int parseData(const QByteArray& packet);
void checkBuffersBeforeFrameSend(int jitterBufferLengthSamples);
void checkBuffersBeforeFrameSend(int jitterBufferLengthSamples,
AABox* checkSourceZone = NULL, AABox* listenerZone = NULL);
void pushBuffersAfterFrameSend();
private:
QList<PositionalAudioRingBuffer*> _ringBuffers;

View file

@ -184,7 +184,8 @@ void OctreeInboundPacketProcessor::trackInboundPacket(const QUuid& nodeUUID, uns
int OctreeInboundPacketProcessor::sendNackPackets() {
int packetsSent = 0;
char packet[MAX_PACKET_SIZE];
NodeToSenderStatsMapIterator i = _singleSenderStats.begin();
while (i != _singleSenderStats.end()) {
@ -206,15 +207,10 @@ int OctreeInboundPacketProcessor::sendNackPackets() {
const SharedNodePointer& destinationNode = NodeList::getInstance()->getNodeHash().value(nodeUUID);
const QSet<unsigned short int>& missingSequenceNumbers = nodeStats.getMissingSequenceNumbers();
// check if there are any sequence numbers that need to be nacked
int numSequenceNumbersAvailable = missingSequenceNumbers.size();
// construct nack packet(s) for this node
QSet<unsigned short int>::const_iterator missingSequenceNumberIterator = missingSequenceNumbers.begin();
char packet[MAX_PACKET_SIZE];
int numSequenceNumbersAvailable = missingSequenceNumbers.size();
QSet<unsigned short int>::const_iterator missingSequenceNumberIterator = missingSequenceNumbers.constBegin();
while (numSequenceNumbersAvailable > 0) {
char* dataAt = packet;
@ -243,8 +239,7 @@ int OctreeInboundPacketProcessor::sendNackPackets() {
numSequenceNumbersAvailable -= numSequenceNumbers;
// send it
qint64 bytesWritten = NodeList::getInstance()->writeUnverifiedDatagram(packet, dataAt - packet, destinationNode);
NodeList::getInstance()->writeUnverifiedDatagram(packet, dataAt - packet, destinationNode);
packetsSent++;
}
i++;

View file

@ -851,7 +851,6 @@ void OctreeServer::readPendingDatagrams() {
// If we got a nack packet, then we're talking to an agent, and we
// need to make sure we have it in our nodeList.
if (matchingNode) {
nodeList->updateNodeWithDataFromPacket(matchingNode, receivedPacket);
OctreeQueryNode* nodeData = (OctreeQueryNode*)matchingNode->getLinkedData();
if (nodeData) {
nodeData->parseNackPacket(receivedPacket);

View file

@ -974,17 +974,27 @@ function mouseMoveEvent(event) {
var pixelPerDegrees = windowDimensions.y / (1 * 360); // the entire height of the window allow you to make 2 full rotations
var STEP = 15;
var delta = Math.floor((event.x - mouseLastPosition.x) / pixelPerDegrees);
//compute delta in pixel
var cameraForward = Quat.getFront(Camera.getOrientation());
var rotationAxis = (!zIsPressed && xIsPressed) ? { x: 1, y: 0, z: 0 } :
(!zIsPressed && !xIsPressed) ? { x: 0, y: 1, z: 0 } :
{ x: 0, y: 0, z: 1 };
rotationAxis = Vec3.multiplyQbyV(selectedModelProperties.modelRotation, rotationAxis);
var orthogonalAxis = Vec3.cross(cameraForward, rotationAxis);
var mouseDelta = { x: event.x - mouseLastPosition
.x, y: mouseLastPosition.y - event.y, z: 0 };
var transformedMouseDelta = Vec3.multiplyQbyV(Camera.getOrientation(), mouseDelta);
var delta = Math.floor(Vec3.dot(transformedMouseDelta, Vec3.normalize(orthogonalAxis)) / pixelPerDegrees);
var STEP = 15;
if (!event.isShifted) {
delta = Math.floor(delta / STEP) * STEP;
delta = Math.round(delta / STEP) * STEP;
}
var rotation = Quat.fromVec3Degrees({
x: (!zIsPressed && xIsPressed) ? delta : 0, // z is pressed
y: (!zIsPressed && !xIsPressed) ? delta : 0, // x is pressed
z: (zIsPressed && !xIsPressed) ? delta : 0 // neither is pressed
x: (!zIsPressed && xIsPressed) ? delta : 0, // x is pressed
y: (!zIsPressed && !xIsPressed) ? delta : 0, // neither is pressed
z: (zIsPressed && !xIsPressed) ? delta : 0 // z is pressed
});
rotation = Quat.multiply(selectedModelProperties.oldRotation, rotation);

View file

@ -2123,19 +2123,19 @@ void Application::updateMyAvatar(float deltaTime) {
const quint64 TOO_LONG_SINCE_LAST_NACK = 1 * USECS_PER_SECOND;
if (sinceLastNack > TOO_LONG_SINCE_LAST_NACK) {
_lastNackTime = now;
sendNack();
sendNackPackets();
}
}
}
void Application::sendNack() {
int Application::sendNackPackets() {
if (Menu::getInstance()->isOptionChecked(MenuOption::DisableNackPackets)) {
return;
return 0;
}
int packetsSent = 0;
char packet[MAX_PACKET_SIZE];
NodeList* nodeList = NodeList::getInstance();
// iterates thru all nodes in NodeList
foreach(const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) {
@ -2146,14 +2146,14 @@ void Application::sendNack() {
|| node->getType() == NodeType::ModelServer)
) {
// if there are octree packets from this node that are waiting to be processed,
// don't send a NACK since the missing packets may be among those waiting packets.
if (_octreeProcessor.hasPacketsToProcessFrom(node)) {
continue;
}
QUuid nodeUUID = node->getUUID();
// if there are octree packets from this node that are waiting to be processed,
// don't send a NACK since the missing packets may be among those waiting packets.
if (_octreeProcessor.hasPacketsToProcessFrom(nodeUUID)) {
continue;
}
_octreeSceneStatsLock.lockForRead();
// retreive octree scene stats of this node
@ -2163,40 +2163,48 @@ void Application::sendNack() {
}
OctreeSceneStats& stats = _octreeServerSceneStats[nodeUUID];
// check if there are any sequence numbers that need to be nacked
int numSequenceNumbersAvailable = stats.getNumSequenceNumbersToNack();
if (numSequenceNumbersAvailable == 0) {
_octreeSceneStatsLock.unlock();
continue;
}
// make copy of missing sequence numbers from stats
const QSet<OCTREE_PACKET_SEQUENCE> missingSequenceNumbers = stats.getMissingSequenceNumbers();
char* dataAt = packet;
int bytesRemaining = MAX_PACKET_SIZE;
// pack header
int numBytesPacketHeader = populatePacketHeader(packet, PacketTypeOctreeDataNack);
dataAt += numBytesPacketHeader;
bytesRemaining -= numBytesPacketHeader;
int numSequenceNumbersRoomFor = (bytesRemaining - sizeof(uint16_t)) / sizeof(OCTREE_PACKET_SEQUENCE);
// calculate and pack the number of sequence numbers
uint16_t numSequenceNumbers = min(numSequenceNumbersAvailable, numSequenceNumbersRoomFor);
uint16_t* numSequenceNumbersAt = (uint16_t*)dataAt;
*numSequenceNumbersAt = numSequenceNumbers;
dataAt += sizeof(uint16_t);
// pack sequence numbers
for (int i = 0; i < numSequenceNumbers; i++) {
OCTREE_PACKET_SEQUENCE* sequenceNumberAt = (OCTREE_PACKET_SEQUENCE*)dataAt;
*sequenceNumberAt = stats.getNextSequenceNumberToNack();
dataAt += sizeof(OCTREE_PACKET_SEQUENCE);
}
_octreeSceneStatsLock.unlock();
nodeList->writeUnverifiedDatagram(packet, dataAt - packet, node);
// construct nack packet(s) for this node
int numSequenceNumbersAvailable = missingSequenceNumbers.size();
QSet<OCTREE_PACKET_SEQUENCE>::const_iterator missingSequenceNumbersIterator = missingSequenceNumbers.constBegin();
while (numSequenceNumbersAvailable > 0) {
char* dataAt = packet;
int bytesRemaining = MAX_PACKET_SIZE;
// pack header
int numBytesPacketHeader = populatePacketHeader(packet, PacketTypeOctreeDataNack);
dataAt += numBytesPacketHeader;
bytesRemaining -= numBytesPacketHeader;
// calculate and pack the number of sequence numbers
int numSequenceNumbersRoomFor = (bytesRemaining - sizeof(uint16_t)) / sizeof(OCTREE_PACKET_SEQUENCE);
uint16_t numSequenceNumbers = min(numSequenceNumbersAvailable, numSequenceNumbersRoomFor);
uint16_t* numSequenceNumbersAt = (uint16_t*)dataAt;
*numSequenceNumbersAt = numSequenceNumbers;
dataAt += sizeof(uint16_t);
// pack sequence numbers
for (int i = 0; i < numSequenceNumbers; i++) {
OCTREE_PACKET_SEQUENCE* sequenceNumberAt = (OCTREE_PACKET_SEQUENCE*)dataAt;
*sequenceNumberAt = *missingSequenceNumbersIterator;
dataAt += sizeof(OCTREE_PACKET_SEQUENCE);
missingSequenceNumbersIterator++;
}
numSequenceNumbersAvailable -= numSequenceNumbers;
// send it
NodeList::getInstance()->writeUnverifiedDatagram(packet, dataAt - packet, node);
packetsSent++;
}
}
}
return packetsSent;
}
void Application::queryOctree(NodeType_t serverType, PacketType packetType, NodeToJurisdictionMap& jurisdictions) {

View file

@ -413,7 +413,7 @@ private:
static void attachNewHeadToNode(Node *newNode);
static void* networkReceive(void* args); // network receive thread
void sendNack();
int sendNackPackets();
MainWindow* _window;
GLCanvas* _glWidget; // our GLCanvas has a couple extra features

View file

@ -28,14 +28,12 @@ PositionalAudioRingBuffer::PositionalAudioRingBuffer(PositionalAudioRingBuffer::
_willBeAddedToMix(false),
_shouldLoopbackForNode(false),
_shouldOutputStarveDebug(true),
_isStereo(isStereo)
_isStereo(isStereo),
_listenerUnattenuatedZone(NULL)
{
}
PositionalAudioRingBuffer::~PositionalAudioRingBuffer() {
}
int PositionalAudioRingBuffer::parseData(const QByteArray& packet) {
// skip the packet header (includes the source UUID)

View file

@ -12,9 +12,10 @@
#ifndef hifi_PositionalAudioRingBuffer_h
#define hifi_PositionalAudioRingBuffer_h
#include <vector>
#include <glm/gtx/quaternion.hpp>
#include <AABox.h>
#include "AudioRingBuffer.h"
class PositionalAudioRingBuffer : public AudioRingBuffer {
@ -25,7 +26,6 @@ public:
};
PositionalAudioRingBuffer(PositionalAudioRingBuffer::Type type, bool isStereo = false);
~PositionalAudioRingBuffer();
int parseData(const QByteArray& packet);
int parsePositionalData(const QByteArray& positionalByteArray);
@ -47,6 +47,9 @@ public:
const glm::vec3& getPosition() const { return _position; }
const glm::quat& getOrientation() const { return _orientation; }
AABox* getListenerUnattenuatedZone() const { return _listenerUnattenuatedZone; }
void setListenerUnattenuatedZone(AABox* listenerUnattenuatedZone) { _listenerUnattenuatedZone = listenerUnattenuatedZone; }
protected:
// disallow copying of PositionalAudioRingBuffer objects
PositionalAudioRingBuffer(const PositionalAudioRingBuffer&);
@ -61,6 +64,7 @@ protected:
bool _isStereo;
float _nextOutputTrailingLoudness;
AABox* _listenerUnattenuatedZone;
};
#endif // hifi_PositionalAudioRingBuffer_h

View file

@ -1,69 +0,0 @@
//
// AABox.h
// libraries/octree/src
//
// Created by Brad Hefta-Gaub on 04/11/13.
// Copyright 2013 High Fidelity, Inc.
//
// Originally from lighthouse3d. Modified to utilize glm::vec3 and clean up to our coding standards
// Simple axis aligned box class.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_AABox_h
#define hifi_AABox_h
#include <glm/glm.hpp>
#include "BoxBase.h"
class AACube;
class AABox {
public:
AABox(const glm::vec3& corner, float size);
AABox(const glm::vec3& corner, const glm::vec3& dimensions);
AABox();
~AABox() {};
void setBox(const glm::vec3& corner, const glm::vec3& scale);
void setBox(const glm::vec3& corner, float scale);
glm::vec3 getVertexP(const glm::vec3& normal) const;
glm::vec3 getVertexN(const glm::vec3& normal) const;
void scale(float scale);
const glm::vec3& getCorner() const { return _corner; }
const glm::vec3& getScale() const { return _scale; }
const glm::vec3& getDimensions() const { return _scale; }
glm::vec3 calcCenter() const;
glm::vec3 calcTopFarLeft() const;
glm::vec3 getVertex(BoxVertex vertex) const;
bool contains(const glm::vec3& point) const;
bool contains(const AABox& otherBox) const;
bool touches(const AABox& otherBox) const;
bool contains(const AACube& otherCube) const;
bool touches(const AACube& otherCube) const;
bool expandedContains(const glm::vec3& point, float expansion) const;
bool expandedIntersectsSegment(const glm::vec3& start, const glm::vec3& end, float expansion) const;
bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face) const;
bool findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration) const;
bool findCapsulePenetration(const glm::vec3& start, const glm::vec3& end, float radius, glm::vec3& penetration) const;
private:
glm::vec3 getClosestPointOnFace(const glm::vec3& point, BoxFace face) const;
glm::vec3 getClosestPointOnFace(const glm::vec4& origin, const glm::vec4& direction, BoxFace face) const;
glm::vec4 getPlane(BoxFace face) const;
static BoxFace getOppositeFace(BoxFace face);
glm::vec3 _corner;
glm::vec3 _scale;
};
#endif // hifi_AABox_h

View file

@ -47,7 +47,6 @@ OctreeSceneStats::OctreeSceneStats() :
_incomingReallyLate(0),
_incomingPossibleDuplicate(0),
_missingSequenceNumbers(),
_sequenceNumbersToNack(),
_incomingFlightTimeAverage(samples),
_jurisdictionRoot(NULL)
{
@ -160,7 +159,6 @@ void OctreeSceneStats::copyFromOther(const OctreeSceneStats& other) {
_incomingPossibleDuplicate = other._incomingPossibleDuplicate;
_missingSequenceNumbers = other._missingSequenceNumbers;
_sequenceNumbersToNack = other._sequenceNumbersToNack;
}
@ -946,7 +944,6 @@ void OctreeSceneStats::trackIncomingOctreePacket(const QByteArray& packet,
qDebug() << "found it in _missingSequenceNumbers";
}
_missingSequenceNumbers.remove(sequence);
_sequenceNumbersToNack.remove(sequence);
_incomingLikelyLost--;
_incomingRecovered++;
}
@ -986,7 +983,6 @@ void OctreeSceneStats::trackIncomingOctreePacket(const QByteArray& packet,
for (int missingSequenceInt = expectedInt; missingSequenceInt < sequenceInt; missingSequenceInt++) {
OCTREE_PACKET_SEQUENCE missingSequence = missingSequenceInt >= 0 ? missingSequenceInt : missingSequenceInt + UINT16_RANGE;
_missingSequenceNumbers << missingSequence;
_sequenceNumbersToNack << missingSequence;
}
_incomingLastSequence = sequence;
@ -1025,7 +1021,6 @@ void OctreeSceneStats::trackIncomingOctreePacket(const QByteArray& packet,
qDebug() << "pruning really old missing sequence:" << missingItem;
}
_missingSequenceNumbers.remove(missingItem);
_sequenceNumbersToNack.remove(missingItem);
}
}
}
@ -1037,14 +1032,3 @@ void OctreeSceneStats::trackIncomingOctreePacket(const QByteArray& packet,
_incomingWastedBytes += (MAX_PACKET_SIZE - packet.size());
}
}
int OctreeSceneStats::getNumSequenceNumbersToNack() const {
return _sequenceNumbersToNack.size();
}
uint16_t OctreeSceneStats::getNextSequenceNumberToNack() {
QSet<uint16_t>::Iterator it = _sequenceNumbersToNack.begin();
uint16_t sequenceNumber = *it;
_sequenceNumbersToNack.remove(sequenceNumber);
return sequenceNumber;
}

View file

@ -172,9 +172,8 @@ public:
quint32 getIncomingReallyLate() const { return _incomingReallyLate; }
quint32 getIncomingPossibleDuplicate() const { return _incomingPossibleDuplicate; }
float getIncomingFlightTimeAverage() { return _incomingFlightTimeAverage.getAverage(); }
int getNumSequenceNumbersToNack() const;
OCTREE_PACKET_SEQUENCE getNextSequenceNumberToNack();
const QSet<OCTREE_PACKET_SEQUENCE>& getMissingSequenceNumbers() const { return _missingSequenceNumbers; }
private:
@ -277,7 +276,6 @@ private:
quint32 _incomingReallyLate; /// out of order and later than MAX_MISSING_SEQUENCE_OLD_AGE late
quint32 _incomingPossibleDuplicate; /// out of order possibly a duplicate
QSet<OCTREE_PACKET_SEQUENCE> _missingSequenceNumbers;
QSet<OCTREE_PACKET_SEQUENCE> _sequenceNumbersToNack;
SimpleMovingAverage _incomingFlightTimeAverage;
// features related items

View file

@ -0,0 +1,71 @@
//
// AABox.h
// libraries/octree/src
//
// Created by Brad Hefta-Gaub on 04/11/13.
// Copyright 2013 High Fidelity, Inc.
//
// Originally from lighthouse3d. Modified to utilize glm::vec3 and clean up to our coding standards
// Simple axis aligned box class.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_AABox_h
#define hifi_AABox_h
#include <glm/glm.hpp>
#include "BoxBase.h"
class AACube;
class AABox {
public:
AABox(const glm::vec3& corner, float size);
AABox(const glm::vec3& corner, const glm::vec3& dimensions);
AABox();
~AABox() {};
void setBox(const glm::vec3& corner, const glm::vec3& scale);
void setBox(const glm::vec3& corner, float scale);
glm::vec3 getVertexP(const glm::vec3& normal) const;
glm::vec3 getVertexN(const glm::vec3& normal) const;
void scale(float scale);
const glm::vec3& getCorner() const { return _corner; }
const glm::vec3& getScale() const { return _scale; }
const glm::vec3& getDimensions() const { return _scale; }
glm::vec3 calcCenter() const;
glm::vec3 calcTopFarLeft() const;
glm::vec3 getVertex(BoxVertex vertex) const;
bool contains(const glm::vec3& point) const;
bool contains(const AABox& otherBox) const;
bool touches(const AABox& otherBox) const;
bool contains(const AACube& otherCube) const;
bool touches(const AACube& otherCube) const;
bool expandedContains(const glm::vec3& point, float expansion) const;
bool expandedIntersectsSegment(const glm::vec3& start, const glm::vec3& end, float expansion) const;
bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face) const;
bool findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration) const;
bool findCapsulePenetration(const glm::vec3& start, const glm::vec3& end, float radius, glm::vec3& penetration) const;
bool isNull() const { return _scale == glm::vec3(0.0f, 0.0f, 0.0f); }
private:
glm::vec3 getClosestPointOnFace(const glm::vec3& point, BoxFace face) const;
glm::vec3 getClosestPointOnFace(const glm::vec4& origin, const glm::vec4& direction, BoxFace face) const;
glm::vec4 getPlane(BoxFace face) const;
static BoxFace getOppositeFace(BoxFace face);
glm::vec3 _corner;
glm::vec3 _scale;
};
#endif // hifi_AABox_h