From 9ea53f8070b11aa37a0866994af4fc4e9c5d2980 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 4 Jun 2014 11:38:46 -0700 Subject: [PATCH 01/52] some testing with editModels --- examples/editModels.js | 76 ++++++++++++++++++++++++++---------------- 1 file changed, 47 insertions(+), 29 deletions(-) diff --git a/examples/editModels.js b/examples/editModels.js index 24ab7da1a1..c2072a46cd 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -152,6 +152,7 @@ function controller(wichSide) { this.jointsIntersectingFromStart.push(i); } } + this.showLaser(false); } } @@ -196,6 +197,7 @@ function controller(wichSide) { this.grabbing = false; this.modelID.isKnownID = false; this.jointsIntersectingFromStart = []; + this.showLaser(true); } this.checkTrigger = function () { @@ -258,41 +260,43 @@ function controller(wichSide) { Overlays.editOverlay(this.laser, { position: startPosition, - end: endPosition, - visible: true + end: endPosition }); Overlays.editOverlay(this.ball, { - position: endPosition, - visible: true + position: endPosition }); Overlays.editOverlay(this.leftRight, { position: Vec3.sum(endPosition, Vec3.multiply(this.right, 2 * this.guideScale)), - end: Vec3.sum(endPosition, Vec3.multiply(this.right, -2 * this.guideScale)), - visible: true + end: Vec3.sum(endPosition, Vec3.multiply(this.right, -2 * this.guideScale)) }); Overlays.editOverlay(this.topDown, {position: Vec3.sum(endPosition, Vec3.multiply(this.up, 2 * this.guideScale)), - end: Vec3.sum(endPosition, Vec3.multiply(this.up, -2 * this.guideScale)), - visible: true + end: Vec3.sum(endPosition, Vec3.multiply(this.up, -2 * this.guideScale)) }); + this.showLaser(!this.grabbing); } - this.hideLaser = function() { - Overlays.editOverlay(this.laser, { visible: false }); - Overlays.editOverlay(this.ball, { visible: false }); - Overlays.editOverlay(this.leftRight, { visible: false }); - Overlays.editOverlay(this.topDown, { visible: false }); + this.showLaser = function(show) { + Overlays.editOverlay(this.laser, { visible: show }); + Overlays.editOverlay(this.ball, { visible: show }); + Overlays.editOverlay(this.leftRight, { visible: show }); + Overlays.editOverlay(this.topDown, { visible: show }); } this.moveModel = function () { if (this.grabbing) { - var newPosition = Vec3.sum(this.palmPosition, - Vec3.multiply(this.front, this.x)); - newPosition = Vec3.sum(newPosition, - Vec3.multiply(this.up, this.y)); - newPosition = Vec3.sum(newPosition, - Vec3.multiply(this.right, this.z)); + var forward = Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -1 }); + var d = Vec3.dot(forward, MyAvatar.position); + + var factor1 = Vec3.dot(forward, this.palmPosition) - d; + var factor2 = Vec3.dot(forward, this.oldModelPosition) - d; + var vector = Vec3.subtract(this.palmPosition, this.oldPalmPosition); + + var newPosition = Vec3.sum(this.oldModelPosition, + Vec3.multiply(vector, + factor2 / factor1)); + var newRotation = Quat.multiply(this.rotation, Quat.inverse(this.oldRotation)); @@ -457,20 +461,34 @@ function moveModels() { var newPosition = Vec3.sum(middle, Vec3.multiply(Vec3.subtract(leftController.oldModelPosition, oldMiddle), ratio)); - //Vec3.print("Ratio : " + ratio + " New position: ", newPosition); - var rotation = Quat.multiply(leftController.rotation, - Quat.inverse(leftController.oldRotation)); + + + var u = Vec3.normalize(Vec3.subtract(rightController.oldPalmPosition, leftController.oldPalmPosition)); + var v = Vec3.normalize(Vec3.subtract(rightController.palmPosition, leftController.palmPosition)); + + var cos_theta = Vec3.dot(Vec3.normalize(u), Vec3.normalize(v)); + var angle = Math.acos(cos_theta); + var w = Vec3.normalize(Vec3.cross(u, v)); + + + var rotation = Quat.angleAxis(angle, w); + + rotation = Quat.multiply(rotation, leftController.oldModelRotation); Models.editModel(leftController.modelID, { - position: newPosition, - //modelRotation: rotation, - radius: leftController.oldModelRadius * ratio + //position: newPosition, + modelRotation: rotation, + //radius: leftController.oldModelRadius * ratio }); - leftController.oldModelPosition = newPosition; + //leftController.oldModelPosition = newPosition; leftController.oldModelRotation = rotation; - leftController.oldModelRadius *= ratio; + //leftController.oldModelRadius *= ratio; + + //rightController.oldModelPosition = newPosition; + rightController.oldModelRotation = rotation; + //rightController.oldModelRadius *= ratio; return; } @@ -498,8 +516,8 @@ function checkController(deltaTime) { if (hydraConnected) { hydraConnected = false; - leftController.hideLaser(); - rightController.hideLaser(); + leftController.showLaser(false); + rightController.showLaser(false); } } From 15863198d1f8a0792361e8af317080aa5cc0f75c Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 4 Jun 2014 13:52:31 -0700 Subject: [PATCH 02/52] change editModels icon --- examples/editModels.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/editModels.js b/examples/editModels.js index c2072a46cd..47da9b0c0a 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -528,7 +528,7 @@ function initToolBar() { toolBar = new ToolBar(0, 0, ToolBar.VERTICAL); // New Model newModel = toolBar.addTool({ - imageURL: toolIconUrl + "voxel-tool.svg", + imageURL: toolIconUrl + "add-model-tool.svg", subImage: { x: 0, y: Tool.IMAGE_WIDTH, width: Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT }, width: toolWidth, height: toolHeight, visible: true, From 79092e3e81a7605c49d38050521c133c92595d88 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 4 Jun 2014 14:18:28 -0700 Subject: [PATCH 03/52] editModels now has 2 modes --- examples/editModels.js | 150 ++++++++++++++++++++++++++++------------- 1 file changed, 102 insertions(+), 48 deletions(-) diff --git a/examples/editModels.js b/examples/editModels.js index 47da9b0c0a..24360c526d 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -42,6 +42,8 @@ var toolBar; var jointList = MyAvatar.getJointNames(); +var mode = 0; + function isLocked(properties) { // special case to lock the ground plane model in hq. if (location.hostname == "hq.highfidelity.io" && @@ -57,6 +59,7 @@ function controller(wichSide) { this.palm = 2 * wichSide; this.tip = 2 * wichSide + 1; this.trigger = wichSide; + this.bumper = 6 * wichSide + 5; this.oldPalmPosition = Controller.getSpatialControlPosition(this.palm); this.palmPosition = Controller.getSpatialControlPosition(this.palm); @@ -77,6 +80,7 @@ function controller(wichSide) { this.rotation = this.oldRotation; this.triggerValue = Controller.getTriggerValue(this.trigger); + this.bumperValue = Controller.isButtonPressed(this.bumper); this.pressed = false; // is trigger pressed this.pressing = false; // is trigger being pressed (is pressed now but wasn't previously) @@ -274,7 +278,7 @@ function controller(wichSide) { Overlays.editOverlay(this.topDown, {position: Vec3.sum(endPosition, Vec3.multiply(this.up, 2 * this.guideScale)), end: Vec3.sum(endPosition, Vec3.multiply(this.up, -2 * this.guideScale)) }); - this.showLaser(!this.grabbing); + this.showLaser(!this.grabbing || mode == 0); } this.showLaser = function(show) { @@ -286,20 +290,44 @@ function controller(wichSide) { this.moveModel = function () { if (this.grabbing) { - var forward = Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -1 }); - var d = Vec3.dot(forward, MyAvatar.position); + var newPosition; + var newRotation; - var factor1 = Vec3.dot(forward, this.palmPosition) - d; - var factor2 = Vec3.dot(forward, this.oldModelPosition) - d; - var vector = Vec3.subtract(this.palmPosition, this.oldPalmPosition); - - var newPosition = Vec3.sum(this.oldModelPosition, - Vec3.multiply(vector, - factor2 / factor1)); + switch (mode) { + case 0: + newPosition = Vec3.sum(this.palmPosition, + Vec3.multiply(this.front, this.x)); + newPosition = Vec3.sum(newPosition, + Vec3.multiply(this.up, this.y)); + newPosition = Vec3.sum(newPosition, + Vec3.multiply(this.right, this.z)); + break; + case 1: + var forward = Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -1 }); + var d = Vec3.dot(forward, MyAvatar.position); + + var factor1 = Vec3.dot(forward, this.palmPosition) - d; + var factor2 = Vec3.dot(forward, this.oldModelPosition) - d; + var vector = Vec3.subtract(this.palmPosition, this.oldPalmPosition); + + if (factor2 < 0) { + factor2 = 0; + } + if (factor1 <= 0) { + factor1 = 1; + factor2 = 1; + } + + newPosition = Vec3.sum(this.oldModelPosition, + Vec3.multiply(vector, + factor2 / factor1)); + break; + } - var newRotation = Quat.multiply(this.rotation, - Quat.inverse(this.oldRotation)); + + newRotation = Quat.multiply(this.rotation, + Quat.inverse(this.oldRotation)); newRotation = Quat.multiply(newRotation, this.oldModelRotation); @@ -345,6 +373,21 @@ function controller(wichSide) { this.triggerValue = Controller.getTriggerValue(this.trigger); + var bumperValue = Controller.isButtonPressed(this.bumper); + if (bumperValue && !this.bumperValue) { + if (mode == 0) { + mode = 1; + Overlays.editOverlay(leftController.laser, { color: { red: 0, green: 0, blue: 255 } }); + Overlays.editOverlay(rightController.laser, { color: { red: 0, green: 0, blue: 255 } }); + } else { + mode = 0; + Overlays.editOverlay(leftController.laser, { color: { red: 255, green: 0, blue: 0 } }); + Overlays.editOverlay(rightController.laser, { color: { red: 255, green: 0, blue: 0 } }); + } + } + this.bumperValue = bumperValue; + + this.checkTrigger(); this.moveLaser(); @@ -443,52 +486,63 @@ var rightController = new controller(RIGHT); function moveModels() { if (leftController.grabbing && rightController.grabbing && rightController.modelID.id == leftController.modelID.id) { - //print("Both controllers"); - var oldLeftPoint = Vec3.sum(leftController.oldPalmPosition, Vec3.multiply(leftController.oldFront, leftController.x)); - var oldRightPoint = Vec3.sum(rightController.oldPalmPosition, Vec3.multiply(rightController.oldFront, rightController.x)); - - var oldMiddle = Vec3.multiply(Vec3.sum(oldLeftPoint, oldRightPoint), 0.5); - var oldLength = Vec3.length(Vec3.subtract(oldLeftPoint, oldRightPoint)); + var newPosition = this.oldModelPosition; + var rotation = this.oldModelRotation; + var ratio = 1; - var leftPoint = Vec3.sum(leftController.palmPosition, Vec3.multiply(leftController.front, leftController.x)); - var rightPoint = Vec3.sum(rightController.palmPosition, Vec3.multiply(rightController.front, rightController.x)); - - var middle = Vec3.multiply(Vec3.sum(leftPoint, rightPoint), 0.5); - var length = Vec3.length(Vec3.subtract(leftPoint, rightPoint)); - - var ratio = length / oldLength; - - var newPosition = Vec3.sum(middle, - Vec3.multiply(Vec3.subtract(leftController.oldModelPosition, oldMiddle), ratio)); - - - var u = Vec3.normalize(Vec3.subtract(rightController.oldPalmPosition, leftController.oldPalmPosition)); - var v = Vec3.normalize(Vec3.subtract(rightController.palmPosition, leftController.palmPosition)); - - var cos_theta = Vec3.dot(Vec3.normalize(u), Vec3.normalize(v)); - var angle = Math.acos(cos_theta); - var w = Vec3.normalize(Vec3.cross(u, v)); - - - var rotation = Quat.angleAxis(angle, w); - - - rotation = Quat.multiply(rotation, leftController.oldModelRotation); + switch (mode) { + case 0: + var oldLeftPoint = Vec3.sum(leftController.oldPalmPosition, Vec3.multiply(leftController.oldFront, leftController.x)); + var oldRightPoint = Vec3.sum(rightController.oldPalmPosition, Vec3.multiply(rightController.oldFront, rightController.x)); + + var oldMiddle = Vec3.multiply(Vec3.sum(oldLeftPoint, oldRightPoint), 0.5); + var oldLength = Vec3.length(Vec3.subtract(oldLeftPoint, oldRightPoint)); + + + var leftPoint = Vec3.sum(leftController.palmPosition, Vec3.multiply(leftController.front, leftController.x)); + var rightPoint = Vec3.sum(rightController.palmPosition, Vec3.multiply(rightController.front, rightController.x)); + + var middle = Vec3.multiply(Vec3.sum(leftPoint, rightPoint), 0.5); + var length = Vec3.length(Vec3.subtract(leftPoint, rightPoint)); + + + ratio = length / oldLength; + newPosition = Vec3.sum(middle, + Vec3.multiply(Vec3.subtract(leftController.oldModelPosition, oldMiddle), ratio)); + break; + case 1: + var u = Vec3.normalize(Vec3.subtract(rightController.oldPalmPosition, leftController.oldPalmPosition)); + var v = Vec3.normalize(Vec3.subtract(rightController.palmPosition, leftController.palmPosition)); + + var cos_theta = Vec3.dot(u, v); + if (cos_theta > 1) { + cos_theta = 1; + } + var angle = Math.acos(cos_theta) / Math.PI * 180; + if (angle < 0.1) { + return; + + } + var w = Vec3.normalize(Vec3.cross(u, v)); + + rotation = Quat.multiply(Quat.angleAxis(angle, w), leftController.oldModelRotation); + break; + } Models.editModel(leftController.modelID, { - //position: newPosition, + position: newPosition, modelRotation: rotation, - //radius: leftController.oldModelRadius * ratio + radius: leftController.oldModelRadius * ratio }); - //leftController.oldModelPosition = newPosition; + leftController.oldModelPosition = newPosition; leftController.oldModelRotation = rotation; - //leftController.oldModelRadius *= ratio; + leftController.oldModelRadius *= ratio; - //rightController.oldModelPosition = newPosition; + rightController.oldModelPosition = newPosition; rightController.oldModelRotation = rotation; - //rightController.oldModelRadius *= ratio; + rightController.oldModelRadius *= ratio; return; } From c1d1a8de5c3bb0aaf23be67190e5cfabfe492836 Mon Sep 17 00:00:00 2001 From: Joseph Gilley Date: Thu, 5 Jun 2014 00:26:45 -0400 Subject: [PATCH 04/52] Fix for users with some special characters in their password not being able to log in using the login overlay in the Interface. --- libraries/networking/src/AccountManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/AccountManager.cpp b/libraries/networking/src/AccountManager.cpp index 7d27332a57..b4aedbcb7c 100644 --- a/libraries/networking/src/AccountManager.cpp +++ b/libraries/networking/src/AccountManager.cpp @@ -313,7 +313,7 @@ void AccountManager::requestAccessToken(const QString& login, const QString& pas QByteArray postData; postData.append("grant_type=password&"); postData.append("username=" + login + "&"); - postData.append("password=" + password + "&"); + postData.append("password=" + QUrl::toPercentEncoding(password) + "&"); postData.append("scope=" + ACCOUNT_MANAGER_REQUESTED_SCOPE); request.setUrl(grantURL); From c44dba78cb3ad4458fe3abb75695967afb763c27 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 5 Jun 2014 15:32:55 -0700 Subject: [PATCH 05/52] Provide a reasonably painless way to stream enums that aren't object properties. --- libraries/metavoxels/src/Bitstream.h | 34 ++++++++++++++++++++++--- tests/metavoxels/src/MetavoxelTests.cpp | 7 +++-- tests/metavoxels/src/MetavoxelTests.h | 3 +++ 3 files changed, 38 insertions(+), 6 deletions(-) diff --git a/libraries/metavoxels/src/Bitstream.h b/libraries/metavoxels/src/Bitstream.h index 146713910f..9945284775 100644 --- a/libraries/metavoxels/src/Bitstream.h +++ b/libraries/metavoxels/src/Bitstream.h @@ -1037,12 +1037,12 @@ public: }; /// Macro for registering simple type streamers. -#define REGISTER_SIMPLE_TYPE_STREAMER(x) static int x##Streamer = \ - Bitstream::registerTypeStreamer(qMetaTypeId(), new SimpleTypeStreamer()); +#define REGISTER_SIMPLE_TYPE_STREAMER(X) static int X##Streamer = \ + Bitstream::registerTypeStreamer(qMetaTypeId(), new SimpleTypeStreamer()); /// Macro for registering collection type streamers. -#define REGISTER_COLLECTION_TYPE_STREAMER(x) static int x##Streamer = \ - Bitstream::registerTypeStreamer(qMetaTypeId(), new CollectionTypeStreamer()); +#define REGISTER_COLLECTION_TYPE_STREAMER(X) static int x##Streamer = \ + Bitstream::registerTypeStreamer(qMetaTypeId(), new CollectionTypeStreamer()); /// Declares the metatype and the streaming operators. The last lines /// ensure that the generated file will be included in the link phase. @@ -1077,6 +1077,25 @@ public: _Pragma(STRINGIFY(unused(_TypePtr##X))) #endif +#define DECLARE_ENUM_METATYPE(S, N) Q_DECLARE_METATYPE(S::N) \ + Bitstream& operator<<(Bitstream& out, const S::N& obj); \ + Bitstream& operator>>(Bitstream& in, S::N& obj); \ + template<> inline void Bitstream::writeRawDelta(const S::N& value, const S::N& reference) { *this << value; } \ + template<> inline void Bitstream::readRawDelta(S::N& value, const S::N& reference) { *this >> value; } + +#define IMPLEMENT_ENUM_METATYPE(S, N) \ + static int S##N##MetaTypeId = registerEnumMetaType(S::staticMetaObject.enumerator( \ + S::staticMetaObject.indexOfEnumerator(#N))); \ + Bitstream& operator<<(Bitstream& out, const S::N& obj) { \ + static int bits = static_cast(Bitstream::getTypeStreamer(qMetaTypeId()))->getBits(); \ + return out.write(&obj, bits); \ + } \ + Bitstream& operator>>(Bitstream& in, S::N& obj) { \ + static int bits = static_cast(Bitstream::getTypeStreamer(qMetaTypeId()))->getBits(); \ + obj = (S::N)0; \ + return in.read(&obj, bits); \ + } + /// Registers a simple type and its streamer. template int registerSimpleMetaType() { int type = qRegisterMetaType(); @@ -1084,6 +1103,13 @@ template int registerSimpleMetaType() { return type; } +/// Registers an enum type and its streamer. +template int registerEnumMetaType(const QMetaEnum& metaEnum) { + int type = qRegisterMetaType(); + Bitstream::registerTypeStreamer(type, new EnumTypeStreamer(metaEnum)); + return type; +} + /// Registers a streamable type and its streamer. template int registerStreamableMetaType() { int type = qRegisterMetaType(); diff --git a/tests/metavoxels/src/MetavoxelTests.cpp b/tests/metavoxels/src/MetavoxelTests.cpp index 603f63b587..cb1b5c7900 100644 --- a/tests/metavoxels/src/MetavoxelTests.cpp +++ b/tests/metavoxels/src/MetavoxelTests.cpp @@ -20,6 +20,8 @@ REGISTER_META_OBJECT(TestSharedObjectA) REGISTER_META_OBJECT(TestSharedObjectB) +IMPLEMENT_ENUM_METATYPE(TestSharedObjectA, TestEnum) + MetavoxelTests::MetavoxelTests(int& argc, char** argv) : QCoreApplication(argc, argv) { } @@ -80,6 +82,7 @@ static TestMessageC createRandomMessageC() { message.bar = rand(); message.baz = randFloat(); message.bong.foo = createRandomBytes(); + message.bong.baz = getRandomTestEnum(); return message; } @@ -252,7 +255,7 @@ static QVariant createRandomMessage() { return QVariant::fromValue(message); } case 1: { - TestMessageB message = { createRandomBytes(), createRandomSharedObject() }; + TestMessageB message = { createRandomBytes(), createRandomSharedObject(), getRandomTestEnum() }; return QVariant::fromValue(message); } case 2: @@ -273,7 +276,7 @@ static bool messagesEqual(const QVariant& firstMessage, const QVariant& secondMe } else if (type == TestMessageB::Type) { TestMessageB first = firstMessage.value(); TestMessageB second = secondMessage.value(); - return first.foo == second.foo && equals(first.bar, second.bar); + return first.foo == second.foo && equals(first.bar, second.bar) && first.baz == second.baz; } else if (type == TestMessageC::Type) { return firstMessage.value() == secondMessage.value(); diff --git a/tests/metavoxels/src/MetavoxelTests.h b/tests/metavoxels/src/MetavoxelTests.h index 5e020b1e60..ffd1311f00 100644 --- a/tests/metavoxels/src/MetavoxelTests.h +++ b/tests/metavoxels/src/MetavoxelTests.h @@ -106,6 +106,8 @@ private: TestFlags _bong; }; +DECLARE_ENUM_METATYPE(TestSharedObjectA, TestEnum) + /// Another simple shared object. class TestSharedObjectB : public SharedObject { Q_OBJECT @@ -169,6 +171,7 @@ public: STREAM QByteArray foo; STREAM SharedObjectPointer bar; + STREAM TestSharedObjectA::TestEnum baz; }; DECLARE_STREAMABLE_METATYPE(TestMessageB) From 887561a4e134e97d30ad11131c83952fc986815c Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 5 Jun 2014 15:39:43 -0700 Subject: [PATCH 06/52] Slight simplification. --- libraries/metavoxels/src/Bitstream.h | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/libraries/metavoxels/src/Bitstream.h b/libraries/metavoxels/src/Bitstream.h index 9945284775..caf0adf7fc 100644 --- a/libraries/metavoxels/src/Bitstream.h +++ b/libraries/metavoxels/src/Bitstream.h @@ -1084,19 +1084,18 @@ public: template<> inline void Bitstream::readRawDelta(S::N& value, const S::N& reference) { *this >> value; } #define IMPLEMENT_ENUM_METATYPE(S, N) \ - static int S##N##MetaTypeId = registerEnumMetaType(S::staticMetaObject.enumerator( \ + static int S##N##Bits = registerEnumMetaType(S::staticMetaObject.enumerator( \ S::staticMetaObject.indexOfEnumerator(#N))); \ Bitstream& operator<<(Bitstream& out, const S::N& obj) { \ - static int bits = static_cast(Bitstream::getTypeStreamer(qMetaTypeId()))->getBits(); \ - return out.write(&obj, bits); \ + return out.write(&obj, S##N##Bits); \ } \ Bitstream& operator>>(Bitstream& in, S::N& obj) { \ - static int bits = static_cast(Bitstream::getTypeStreamer(qMetaTypeId()))->getBits(); \ obj = (S::N)0; \ - return in.read(&obj, bits); \ + return in.read(&obj, S##N##Bits); \ } /// Registers a simple type and its streamer. +/// \return the metatype id template int registerSimpleMetaType() { int type = qRegisterMetaType(); Bitstream::registerTypeStreamer(type, new SimpleTypeStreamer()); @@ -1104,13 +1103,16 @@ template int registerSimpleMetaType() { } /// Registers an enum type and its streamer. +/// \return the number of bits required to stream the enum template int registerEnumMetaType(const QMetaEnum& metaEnum) { int type = qRegisterMetaType(); - Bitstream::registerTypeStreamer(type, new EnumTypeStreamer(metaEnum)); - return type; + EnumTypeStreamer* streamer = new EnumTypeStreamer(metaEnum); + Bitstream::registerTypeStreamer(type, streamer); + return streamer->getBits(); } /// Registers a streamable type and its streamer. +/// \return the metatype id template int registerStreamableMetaType() { int type = qRegisterMetaType(); Bitstream::registerTypeStreamer(type, new StreamableTypeStreamer()); @@ -1118,6 +1120,7 @@ template int registerStreamableMetaType() { } /// Registers a collection type and its streamer. +/// \return the metatype id template int registerCollectionMetaType() { int type = qRegisterMetaType(); Bitstream::registerTypeStreamer(type, new CollectionTypeStreamer()); From 145a159233604285fb2f180e9111fd677b601e1b Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 5 Jun 2014 15:45:25 -0700 Subject: [PATCH 07/52] Slight glow on laser intersection --- examples/editModels.js | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/examples/editModels.js b/examples/editModels.js index 24360c526d..8e2f6b4911 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -252,6 +252,7 @@ function controller(wichSide) { return { valid: false }; } + this.glowedIntersectingModel = { isKnownID: false }; this.moveLaser = function () { // the overlays here are anchored to the avatar, which means they are specified in the avatar's local frame @@ -279,6 +280,22 @@ function controller(wichSide) { end: Vec3.sum(endPosition, Vec3.multiply(this.up, -2 * this.guideScale)) }); this.showLaser(!this.grabbing || mode == 0); + + + if (!this.grabbing) { + if (this.glowedIntersectingModel.isKnownID) { + Models.editModel(this.glowedIntersectingModel, { glowLevel: 0.0 }); + } + + var intersection = Models.findRayIntersection({ + origin: this.palmPosition, + direction: this.front + }); + if (intersection.accurate && intersection.modelID.isKnownID) { + this.glowedIntersectingModel = intersection.modelID; + Models.editModel(this.glowedIntersectingModel, { glowLevel: 0.25 }); + } + } } this.showLaser = function(show) { From 0bdd20abc9d06a8d986a44c0232cd8c75dbc6ea7 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 5 Jun 2014 15:46:07 -0700 Subject: [PATCH 08/52] Coding Standard --- libraries/models/src/ModelTree.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/models/src/ModelTree.cpp b/libraries/models/src/ModelTree.cpp index e88a969061..466d4c5273 100644 --- a/libraries/models/src/ModelTree.cpp +++ b/libraries/models/src/ModelTree.cpp @@ -185,7 +185,7 @@ void ModelTree::addModel(const ModelItemID& modelID, const ModelItemProperties& glm::vec3 position = model.getPosition(); float size = std::max(MINIMUM_MODEL_ELEMENT_SIZE, model.getRadius()); - ModelTreeElement* element = (ModelTreeElement*)getOrCreateChildElementAt(position.x, position.y, position.z, size); + ModelTreeElement* element = static_cast(getOrCreateChildElementAt(position.x, position.y, position.z, size)); element->storeModel(model); _isDirty = true; From 150477eea44d0438137333499fcda498072c76ea Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 5 Jun 2014 15:47:25 -0700 Subject: [PATCH 09/52] Models.addModel now returns a more accurate modelID --- libraries/models/src/ModelItem.cpp | 31 +++++-------------- libraries/models/src/ModelItem.h | 1 + .../models/src/ModelsScriptingInterface.cpp | 3 +- 3 files changed, 11 insertions(+), 24 deletions(-) diff --git a/libraries/models/src/ModelItem.cpp b/libraries/models/src/ModelItem.cpp index b6f4fe6c1d..810129a81f 100644 --- a/libraries/models/src/ModelItem.cpp +++ b/libraries/models/src/ModelItem.cpp @@ -47,6 +47,12 @@ uint32_t ModelItem::getNextCreatorTokenID() { return creatorTokenID; } +uint32_t ModelItem::getNextModelItemID() { + uint32_t modelID = _nextID; + _nextID++; + return modelID; +} + void ModelItem::handleAddModelResponse(const QByteArray& packet) { const unsigned char* dataAt = reinterpret_cast(packet.data()); int numBytesPacketHeader = numBytesForPacketHeader(packet); @@ -70,31 +76,10 @@ ModelItem::ModelItem() { } ModelItem::ModelItem(const ModelItemID& modelItemID, const ModelItemProperties& properties) { - _id = modelItemID.id; _creatorTokenID = modelItemID.creatorTokenID; - - // init values with defaults before calling setProperties - uint64_t now = usecTimestampNow(); - _lastEdited = now; - _lastUpdated = now; - - _position = glm::vec3(0,0,0); - _radius = 0; - rgbColor noColor = { 0, 0, 0 }; - memcpy(_color, noColor, sizeof(_color)); - _shouldDie = false; - _modelURL = MODEL_DEFAULT_MODEL_URL; - _modelRotation = MODEL_DEFAULT_MODEL_ROTATION; - // animation related - _animationURL = MODEL_DEFAULT_ANIMATION_URL; - _animationIsPlaying = false; - _animationFrameIndex = 0.0f; - _animationFPS = MODEL_DEFAULT_ANIMATION_FPS; - _glowLevel = 0.0f; - - _jointMappingCompleted = false; - _lastAnimated = now; + rgbColor defaultColor = { 0, 0, 0 }; + init(glm::vec3(), 0.0f, defaultColor, modelItemID.id); setProperties(properties); } diff --git a/libraries/models/src/ModelItem.h b/libraries/models/src/ModelItem.h index 9a558f2ef4..563d394419 100644 --- a/libraries/models/src/ModelItem.h +++ b/libraries/models/src/ModelItem.h @@ -276,6 +276,7 @@ public: // these methods allow you to create models, and later edit them. static uint32_t getIDfromCreatorTokenID(uint32_t creatorTokenID); static uint32_t getNextCreatorTokenID(); + static uint32_t getNextModelItemID(); static void handleAddModelResponse(const QByteArray& packet); void mapJoints(const QStringList& modelJointNames); diff --git a/libraries/models/src/ModelsScriptingInterface.cpp b/libraries/models/src/ModelsScriptingInterface.cpp index 7e08571fe5..f4cbf14086 100644 --- a/libraries/models/src/ModelsScriptingInterface.cpp +++ b/libraries/models/src/ModelsScriptingInterface.cpp @@ -28,8 +28,9 @@ ModelItemID ModelsScriptingInterface::addModel(const ModelItemProperties& proper // The application will keep track of creatorTokenID uint32_t creatorTokenID = ModelItem::getNextCreatorTokenID(); + uint32_t modelID = ModelItem::getNextModelItemID(); - ModelItemID id(NEW_MODEL, creatorTokenID, false ); + ModelItemID id(modelID, creatorTokenID, false ); // queue the packet queueModelMessage(PacketTypeModelAddOrEdit, id, properties); From c333fb904f88fa109a8776bd5a8a11b8ed17bbd0 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 5 Jun 2014 16:45:13 -0700 Subject: [PATCH 10/52] Working on tests for delta streaming. --- tests/metavoxels/src/MetavoxelTests.cpp | 32 ++++++++++++++++++++++++- tests/metavoxels/src/MetavoxelTests.h | 21 ++++++++++++++++ 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/tests/metavoxels/src/MetavoxelTests.cpp b/tests/metavoxels/src/MetavoxelTests.cpp index cb1b5c7900..c4d973ad05 100644 --- a/tests/metavoxels/src/MetavoxelTests.cpp +++ b/tests/metavoxels/src/MetavoxelTests.cpp @@ -229,6 +229,20 @@ Endpoint::Endpoint(const QByteArray& datagramHeader) : connect(_sequencer, SIGNAL(receivedHighPriorityMessage(const QVariant&)), SLOT(handleHighPriorityMessage(const QVariant&))); + connect(_sequencer, SIGNAL(sendAcknowledged(int)), SLOT(clearSendRecordsBefore(int))); + connect(_sequencer, SIGNAL(receiveAcknowledged(int)), SLOT(clearReceiveRecordsBefore(int))); + + // insert the baseline send record + SendRecord sendRecord = { 0 }; + _sendRecords.append(sendRecord); + + // insert the baseline receive record + ReceiveRecord receiveRecord = { 0 }; + _receiveRecords.append(receiveRecord); + + // create the object that represents out delta-encoded state + //_localState = new TestSharedObjectA(); + connect(_sequencer->getReliableInputChannel(), SIGNAL(receivedMessage(const QVariant&)), SLOT(handleReliableMessage(const QVariant&))); @@ -326,7 +340,7 @@ bool Endpoint::simulate(int iterationNumber) { // send a packet try { Bitstream& out = _sequencer->startPacket(); - SequencedTestMessage message = { iterationNumber, createRandomMessage() }; + SequencedTestMessage message = { iterationNumber, createRandomMessage(), _localState }; _unreliableMessagesSent.append(message); unreliableMessagesSent++; out << message; @@ -337,6 +351,10 @@ bool Endpoint::simulate(int iterationNumber) { return true; } + // record the send + SendRecord record = { _sequencer->getOutgoingPacketNumber(), _localState }; + _sendRecords.append(record); + return false; } @@ -387,6 +405,10 @@ void Endpoint::readMessage(Bitstream& in) { SequencedTestMessage message; in >> message; + // record the receipt + ReceiveRecord record = { _sequencer->getIncomingPacketNumber(), message.state }; + _receiveRecords.append(record); + for (QList::iterator it = _other->_unreliableMessagesSent.begin(); it != _other->_unreliableMessagesSent.end(); it++) { if (it->sequenceNumber == message.sequenceNumber) { @@ -430,6 +452,14 @@ void Endpoint::readReliableChannel() { streamedBytesReceived += bytes.size(); } +void Endpoint::clearSendRecordsBefore(int index) { + _sendRecords.erase(_sendRecords.begin(), _sendRecords.begin() + index + 1); +} + +void Endpoint::clearReceiveRecordsBefore(int index) { + _receiveRecords.erase(_receiveRecords.begin(), _receiveRecords.begin() + index + 1); +} + TestSharedObjectA::TestSharedObjectA(float foo, TestEnum baz, TestFlags bong) : _foo(foo), _baz(baz), diff --git a/tests/metavoxels/src/MetavoxelTests.h b/tests/metavoxels/src/MetavoxelTests.h index ffd1311f00..dc294692af 100644 --- a/tests/metavoxels/src/MetavoxelTests.h +++ b/tests/metavoxels/src/MetavoxelTests.h @@ -54,9 +54,29 @@ private slots: void handleReliableMessage(const QVariant& message); void readReliableChannel(); + void clearSendRecordsBefore(int index); + void clearReceiveRecordsBefore(int index); + private: + class SendRecord { + public: + int packetNumber; + SharedObjectPointer localState; + }; + + class ReceiveRecord { + public: + int packetNumber; + SharedObjectPointer remoteState; + }; + DatagramSequencer* _sequencer; + QList _sendRecords; + QList _receiveRecords; + + SharedObjectPointer _localState; + Endpoint* _other; QList > _delayedDatagrams; float _highPriorityMessagesToSend; @@ -195,6 +215,7 @@ public: STREAM int sequenceNumber; STREAM QVariant submessage; + STREAM SharedObjectPointer state; }; DECLARE_STREAMABLE_METATYPE(SequencedTestMessage) From 005a314695545fd1c9d24a6161f4e6bff77c0928 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 5 Jun 2014 17:30:19 -0700 Subject: [PATCH 11/52] Reenable enum streamers here. --- libraries/metavoxels/src/Bitstream.cpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/libraries/metavoxels/src/Bitstream.cpp b/libraries/metavoxels/src/Bitstream.cpp index 387b41a839..30d34580d7 100644 --- a/libraries/metavoxels/src/Bitstream.cpp +++ b/libraries/metavoxels/src/Bitstream.cpp @@ -92,14 +92,13 @@ int Bitstream::registerMetaObject(const char* className, const QMetaObject* meta } // register the streamers for all enumerators - // temporarily disabled: crashes on Windows - //for (int i = 0; i < metaObject->enumeratorCount(); i++) { - // QMetaEnum metaEnum = metaObject->enumerator(i); - // const TypeStreamer*& streamer = getEnumStreamers()[QPair(metaEnum.scope(), metaEnum.name())]; - // if (!streamer) { - // getEnumStreamersByName().insert(getEnumName(metaEnum), streamer = new EnumTypeStreamer(metaEnum)); - // } - //} + for (int i = 0; i < metaObject->enumeratorCount(); i++) { + QMetaEnum metaEnum = metaObject->enumerator(i); + const TypeStreamer*& streamer = getEnumStreamers()[QPair(metaEnum.scope(), metaEnum.name())]; + if (!streamer) { + getEnumStreamersByName().insert(getEnumName(metaEnum), streamer = new EnumTypeStreamer(metaEnum)); + } + } return 0; } From 9322e1f71b5d3e0f31127f3ef3b1762a24bdcd4f Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 5 Jun 2014 17:36:56 -0700 Subject: [PATCH 12/52] More work on editModels --- examples/editModels.js | 205 ++++++++++++++++++++++++++++------------- 1 file changed, 139 insertions(+), 66 deletions(-) diff --git a/examples/editModels.js b/examples/editModels.js index 8e2f6b4911..67e2bdb198 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -18,7 +18,8 @@ var toolWidth = 50; var LASER_WIDTH = 4; var LASER_COLOR = { red: 255, green: 0, blue: 0 }; -var LASER_LENGTH_FACTOR = 5; +var LASER_LENGTH_FACTOR = 500 +; var LEFT = 0; var RIGHT = 1; @@ -92,6 +93,11 @@ function controller(wichSide) { this.oldModelPosition; this.oldModelRadius; + this.positionAtGrab; + this.rotationAtGrab; + this.modelPositionAtGrab; + this.modelRotationAtGrab; + this.jointsIntersectingFromStart = []; this.laser = Overlays.addOverlay("line3d", { @@ -149,6 +155,11 @@ function controller(wichSide) { this.oldModelRotation = properties.modelRotation; this.oldModelRadius = properties.radius; + this.positionAtGrab = this.palmPosition; + this.rotationAtGrab = this.rotation; + this.modelPositionAtGrab = properties.position; + this.modelRotationAtGrab = properties.modelRotation; + this.jointsIntersectingFromStart = []; for (var i = 0; i < jointList.length; i++) { var distance = Vec3.distance(MyAvatar.getJointPosition(jointList[i]), this.oldModelPosition); @@ -174,12 +185,16 @@ function controller(wichSide) { } } - print("closestJoint: " + jointList[closestJointIndex]); - print("closestJointDistance (attach max distance): " + closestJointDistance + " (" + this.oldModelRadius + ")"); + if (closestJointIndex != -1) { + print("closestJoint: " + jointList[closestJointIndex]); + print("closestJointDistance (attach max distance): " + closestJointDistance + " (" + this.oldModelRadius + ")"); + } if (closestJointDistance < this.oldModelRadius) { - if (this.jointsIntersectingFromStart.indexOf(closestJointIndex) != -1) { + if (this.jointsIntersectingFromStart.indexOf(closestJointIndex) != -1 || + (leftController.grabbing && rightController.grabbing && + leftController.modelID.id == rightController.modelID.id)) { // Do nothing } else { print("Attaching to " + jointList[closestJointIndex]); @@ -193,6 +208,7 @@ function controller(wichSide) { MyAvatar.attach(this.modelURL, jointList[closestJointIndex], attachmentOffset, attachmentRotation, 2.0 * this.oldModelRadius, true, false); + Models.deleteModel(this.modelID); } } @@ -281,12 +297,11 @@ function controller(wichSide) { }); this.showLaser(!this.grabbing || mode == 0); - + if (this.glowedIntersectingModel.isKnownID) { + Models.editModel(this.glowedIntersectingModel, { glowLevel: 0.0 }); + this.glowedIntersectingModel.isKnownID = false; + } if (!this.grabbing) { - if (this.glowedIntersectingModel.isKnownID) { - Models.editModel(this.glowedIntersectingModel, { glowLevel: 0.0 }); - } - var intersection = Models.findRayIntersection({ origin: this.palmPosition, direction: this.front @@ -307,6 +322,14 @@ function controller(wichSide) { this.moveModel = function () { if (this.grabbing) { + if (!this.modelID.isKnownID) { + print("Unknown grabbed ID " + this.modelID.id + ", isKnown: " + this.modelID.isKnownID); + this.modelID = Models.findRayIntersection({ + origin: this.palmPosition, + direction: this.front + }).modelID; + print("Identified ID " + this.modelID.id + ", isKnown: " + this.modelID.isKnownID); + } var newPosition; var newRotation; @@ -318,15 +341,22 @@ function controller(wichSide) { Vec3.multiply(this.up, this.y)); newPosition = Vec3.sum(newPosition, Vec3.multiply(this.right, this.z)); + + + newRotation = Quat.multiply(this.rotation, + Quat.inverse(this.oldRotation)); + newRotation = Quat.multiply(newRotation, + this.oldModelRotation); break; case 1: var forward = Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -1 }); var d = Vec3.dot(forward, MyAvatar.position); - var factor1 = Vec3.dot(forward, this.palmPosition) - d; - var factor2 = Vec3.dot(forward, this.oldModelPosition) - d; - var vector = Vec3.subtract(this.palmPosition, this.oldPalmPosition); + var factor1 = Vec3.dot(forward, this.positionAtGrab) - d; + var factor2 = Vec3.dot(forward, this.modelPositionAtGrab) - d; + var vector = Vec3.subtract(this.palmPosition, this.positionAtGrab); + print("factor1: " + factor1 + ", factor2: " + factor2); if (factor2 < 0) { factor2 = 0; } @@ -335,19 +365,17 @@ function controller(wichSide) { factor2 = 1; } - newPosition = Vec3.sum(this.oldModelPosition, + newPosition = Vec3.sum(this.modelPositionAtGrab, Vec3.multiply(vector, factor2 / factor1)); + + newRotation = Quat.multiply(this.rotation, + Quat.inverse(this.rotationAtGrab)); + newRotation = Quat.multiply(newRotation, + this.modelRotationAtGrab); break; } - - - newRotation = Quat.multiply(this.rotation, - Quat.inverse(this.oldRotation)); - newRotation = Quat.multiply(newRotation, - this.oldModelRotation); - Models.editModel(this.modelID, { position: newPosition, modelRotation: newRotation @@ -367,8 +395,46 @@ function controller(wichSide) { for (var i = 0; i < indicesToRemove.length; ++i) { this.jointsIntersectingFromStart.splice(this.jointsIntersectingFromStart.indexOf(indicesToRemove[i], 1)); } + + + jointList = MyAvatar.getJointNames(); + + var closestJointIndex = -1; + var closestJointDistance = 999999; + for (var i = 0; i < jointList.length; i++) { + var distance = Vec3.distance(MyAvatar.getJointPosition(jointList[i]), this.oldModelPosition); + if (distance < closestJointDistance) { + closestJointDistance = distance; + closestJointIndex = i; + } + } + + if (closestJointDistance < this.oldModelRadius) { + if (this.jointsIntersectingFromStart.indexOf(closestJointIndex) != -1 || + (leftController.grabbing && rightController.grabbing && + leftController.modelID.id == rightController.modelID.id)) { + // Do nothing + } else { + Vec3.print("Ball at: ", MyAvatar.getJointPosition(closestJointIndex)); + Overlays.editOverlay(this.ballGlowingJoint, { + position: MyAvatar.getJointPosition(closestJointIndex), + glowLevel: 0.25, + visible: true + }); + } + } else { + Overlays.editOverlay(this.ballGlowingJoint, { glowLevel: 0.0, visible: false }); + } } } + this.ballGlowingJoint = Overlays.addOverlay("sphere", { + position: { x: 0, y: 0, z: 0 }, + size: 1, + solid: true, + color: { red: 0, green: 255, blue: 0 }, + alpha: 1, + visible: false, + anchor: "MyAvatar"}); this.update = function () { this.oldPalmPosition = this.palmPosition; @@ -420,8 +486,12 @@ function controller(wichSide) { var attachmentIndex = -1; var attachmentX = LASER_LENGTH_FACTOR; + var newModel; + var newProperties; + for (var i = 0; i < attachments.length; ++i) { - var position = Vec3.sum(MyAvatar.getJointPosition(attachments[i].jointName), attachments[i].translation); + var position = Vec3.sum(MyAvatar.getJointPosition(attachments[i].jointName), + Vec3.multiplyQbyV(MyAvatar.getJointCombinedRotation(attachments[i].jointName), attachments[i].translation)); var scale = attachments[i].scale; var A = this.palmPosition; @@ -439,53 +509,56 @@ function controller(wichSide) { } if (attachmentIndex != -1) { + print("Detaching: " + attachments[attachmentIndex].modelURL); MyAvatar.detachOne(attachments[attachmentIndex].modelURL, attachments[attachmentIndex].jointName); - Models.addModel({ - position: Vec3.sum(MyAvatar.getJointPosition(attachments[attachmentIndex].jointName), - attachments[attachmentIndex].translation), - modelRotation: Quat.multiply(MyAvatar.getJointCombinedRotation(attachments[attachmentIndex].jointName), - attachments[attachmentIndex].rotation), - radius: attachments[attachmentIndex].scale / 2.0, - modelURL: attachments[attachmentIndex].modelURL - }); - } - - // There is none so ... - // Checking model tree - Vec3.print("Looking at: ", this.palmPosition); - var pickRay = { origin: this.palmPosition, - direction: Vec3.normalize(Vec3.subtract(this.tipPosition, this.palmPosition)) }; - var foundIntersection = Models.findRayIntersection(pickRay); - - if(!foundIntersection.accurate) { - return; - } - var foundModel = foundIntersection.modelID; - - if (!foundModel.isKnownID) { - var identify = Models.identifyModel(foundModel); - if (!identify.isKnownID) { - print("Unknown ID " + identify.id + " (update loop " + foundModel.id + ")"); - return; - } - foundModel = identify; - } - - var properties = Models.getModelProperties(foundModel); - print("foundModel.modelURL=" + properties.modelURL); - - if (isLocked(properties)) { - print("Model locked " + properties.id); + + newProperties = { + position: Vec3.sum(MyAvatar.getJointPosition(attachments[attachmentIndex].jointName), + Vec3.multiplyQbyV(MyAvatar.getJointCombinedRotation(attachments[attachmentIndex].jointName), attachments[attachmentIndex].translation)), + modelRotation: Quat.multiply(MyAvatar.getJointCombinedRotation(attachments[attachmentIndex].jointName), + attachments[attachmentIndex].rotation), + radius: attachments[attachmentIndex].scale / 2.0, + modelURL: attachments[attachmentIndex].modelURL + }; + newModel = Models.addModel(newProperties); } else { - print("Checking properties: " + properties.id + " " + properties.isKnownID); - var check = this.checkModel(properties); - if (check.valid) { - this.grab(foundModel, properties); - this.x = check.x; - this.y = check.y; - this.z = check.z; + // There is none so ... + // Checking model tree + Vec3.print("Looking at: ", this.palmPosition); + var pickRay = { origin: this.palmPosition, + direction: Vec3.normalize(Vec3.subtract(this.tipPosition, this.palmPosition)) }; + var foundIntersection = Models.findRayIntersection(pickRay); + + if(!foundIntersection.accurate) { + print("No accurate intersection"); return; } + newModel = foundIntersection.modelID; + + if (!newModel.isKnownID) { + var identify = Models.identifyModel(newModel); + if (!identify.isKnownID) { + print("Unknown ID " + identify.id + " (update loop " + newModel.id + ")"); + return; + } + newModel = identify; + } + newProperties = Models.getModelProperties(newModel); + } + + + print("foundModel.modelURL=" + newProperties.modelURL); + + if (isLocked(newProperties)) { + print("Model locked " + newProperties.id); + } else { + this.grab(newModel, newProperties); + + var check = this.checkModel(newProperties); + this.x = check.x; + this.y = check.y; + this.z = check.z; + return; } } } @@ -503,8 +576,8 @@ var rightController = new controller(RIGHT); function moveModels() { if (leftController.grabbing && rightController.grabbing && rightController.modelID.id == leftController.modelID.id) { - var newPosition = this.oldModelPosition; - var rotation = this.oldModelRotation; + var newPosition = leftController.oldModelPosition; + var rotation = leftController.oldModelRotation; var ratio = 1; From 1a7e3a859cafe5c344b912b221580f12981abd92 Mon Sep 17 00:00:00 2001 From: wangyix Date: Thu, 5 Jun 2014 18:00:58 -0700 Subject: [PATCH 13/52] started work on resending nacked packets --- assignment-client/src/models/ModelServer.cpp | 2 +- .../src/octree/OctreeQueryNode.cpp | 35 ++++++++++++++- .../src/octree/OctreeQueryNode.h | 16 ++++++- .../src/octree/OctreeSendThread.cpp | 36 ++++++++++++++- .../src/octree/OctreeSendThread.h | 3 ++ assignment-client/src/octree/OctreeServer.cpp | 28 ++++++++++-- .../src/octree/SentPacketHistory.cpp | 45 +++++++++++++++++++ .../src/octree/SentPacketHistory.h | 36 +++++++++++++++ .../src/particles/ParticleServer.cpp | 2 +- assignment-client/src/voxels/VoxelServer.cpp | 2 +- libraries/networking/src/PacketHeaders.h | 1 + 11 files changed, 196 insertions(+), 10 deletions(-) create mode 100644 assignment-client/src/octree/SentPacketHistory.cpp create mode 100644 assignment-client/src/octree/SentPacketHistory.h diff --git a/assignment-client/src/models/ModelServer.cpp b/assignment-client/src/models/ModelServer.cpp index ff2367ec6e..07359f001a 100644 --- a/assignment-client/src/models/ModelServer.cpp +++ b/assignment-client/src/models/ModelServer.cpp @@ -106,7 +106,7 @@ int ModelServer::sendSpecialPacket(OctreeQueryNode* queryNode, const SharedNodeP //qDebug() << "sending PacketType_MODEL_ERASE packetLength:" << packetLength; NodeList::getInstance()->writeDatagram((char*) outputBuffer, packetLength, SharedNodePointer(node)); - queryNode->incrementSequenceNumber(); + queryNode->packetSent(outputBuffer, packetLength); } nodeData->setLastDeletedModelsSentAt(deletePacketSentAt); diff --git a/assignment-client/src/octree/OctreeQueryNode.cpp b/assignment-client/src/octree/OctreeQueryNode.cpp index 6acd85bff6..e0ca6a4f1e 100644 --- a/assignment-client/src/octree/OctreeQueryNode.cpp +++ b/assignment-client/src/octree/OctreeQueryNode.cpp @@ -41,7 +41,8 @@ OctreeQueryNode::OctreeQueryNode() : _sequenceNumber(0), _lastRootTimestamp(0), _myPacketType(PacketTypeUnknown), - _isShuttingDown(false) + _isShuttingDown(false), + _sentPacketHistory(1000) { } @@ -362,3 +363,35 @@ void OctreeQueryNode::dumpOutOfView() { } } } + +void OctreeQueryNode::packetSent() { + packetSent(_octreePacket, getPacketLength()); +} + +void OctreeQueryNode::packetSent(unsigned char* packet, int packetLength) { + packetSent(QByteArray((char*)packet, packetLength)); +} + +void OctreeQueryNode::packetSent(const QByteArray& packet) { + _sentPacketHistory.packetSent(_sequenceNumber, packet); + _sequenceNumber++; +} + + +void OctreeQueryNode::addSequenceNumbersToResend(const QList& sequenceNumbers) { + _sequenceNumbersToResend.append(sequenceNumbers); +} + +bool OctreeQueryNode::hasNextPacketToResend() const { + return !_sequenceNumbersToResend.isEmpty(); +} + +const QByteArray* OctreeQueryNode::getNextPacketToResend() { + + if (!_sequenceNumbersToResend.isEmpty()) { + const QByteArray* nextPacket = _sentPacketHistory.getPacket(_sequenceNumbersToResend.first()); + _sequenceNumbersToResend.pop_front(); + return nextPacket; // could be null + } + return NULL; +} \ No newline at end of file diff --git a/assignment-client/src/octree/OctreeQueryNode.h b/assignment-client/src/octree/OctreeQueryNode.h index eb420039e6..4a2355f7cc 100644 --- a/assignment-client/src/octree/OctreeQueryNode.h +++ b/assignment-client/src/octree/OctreeQueryNode.h @@ -23,6 +23,9 @@ #include #include #include // for SharedAssignmentPointer +#include "SentPacketHistory.h" + +#include // i added dis class OctreeSendThread; @@ -100,10 +103,16 @@ public: void forceNodeShutdown(); bool isShuttingDown() const { return _isShuttingDown; } - void incrementSequenceNumber() { _sequenceNumber++; } + void packetSent(); + void packetSent(unsigned char* packet, int packetLength); + void packetSent(const QByteArray& packet); OCTREE_PACKET_SEQUENCE getSequenceNumber() const { return _sequenceNumber; } - + + void addSequenceNumbersToResend(const QList& sequenceNumbers); + bool hasNextPacketToResend() const; + const QByteArray* getNextPacketToResend(); + private slots: void sendThreadFinished(); @@ -146,6 +155,9 @@ private: PacketType _myPacketType; bool _isShuttingDown; + +SentPacketHistory _sentPacketHistory; +QQueue _sequenceNumbersToResend; }; #endif // hifi_OctreeQueryNode_h diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index 9e4dbcd347..5767f2623b 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -274,13 +274,47 @@ int OctreeSendThread::handlePacketSend(OctreeQueryNode* nodeData, int& trueBytes trueBytesSent += nodeData->getPacketLength(); truePacketsSent++; packetsSent++; - nodeData->incrementSequenceNumber(); + nodeData->packetSent(); nodeData->resetOctreePacket(); } return packetsSent; } + + + + +int OctreeSendThread::resendNackedPackets(OctreeQueryNode* nodeData) { + + int packetsSent = 0; + + const QByteArray* packet; + while (nodeData->hasNextPacketToResend()) { + packet = nodeData->getNextPacketToResend(); + if (packet) { + NodeList::getInstance()->writeDatagram(*packet, _node); + packetsSent++; + + // ?????? + _totalBytes += packet->size(); + _totalPackets++; + _totalWastedBytes += MAX_PACKET_SIZE - packet->size(); // ??? + } + } + +} + + + + + + + + + + + /// Version of voxel distributor that sends the deepest LOD level at once int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrustumChanged) { diff --git a/assignment-client/src/octree/OctreeSendThread.h b/assignment-client/src/octree/OctreeSendThread.h index d8eed27802..cc0cdac3ad 100644 --- a/assignment-client/src/octree/OctreeSendThread.h +++ b/assignment-client/src/octree/OctreeSendThread.h @@ -55,6 +55,9 @@ private: int _nodeMissingCount; bool _isShuttingDown; + +int resendNackedPackets(OctreeQueryNode* nodeData); + }; #endif // hifi_OctreeSendThread_h diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index 5769c15ef1..f60f0fc2d5 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -832,14 +832,14 @@ void OctreeServer::readPendingDatagrams() { PacketType packetType = packetTypeForPacket(receivedPacket); SharedNodePointer matchingNode = nodeList->sendingNodeForPacket(receivedPacket); if (packetType == getMyQueryMessageType()) { - + // If we got a query 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(); + OctreeQueryNode* nodeData = (OctreeQueryNode*)matchingNode->getLinkedData(); if (nodeData && !nodeData->isOctreeSendThreadInitalized()) { - + // NOTE: this is an important aspect of the proper ref counting. The send threads/node data need to // know that the OctreeServer/Assignment will not get deleted on it while it's still active. The // solution is to get the shared pointer for the current assignment. We need to make sure this is the @@ -848,6 +848,28 @@ void OctreeServer::readPendingDatagrams() { nodeData->initializeOctreeSendThread(sharedAssignment, matchingNode); } } + + } else if (packetType == PacketTypeOctreeDataNack) { + +// parse packet for sequence numbers that need to be resent +int numBytesPacketHeader = numBytesForPacketHeader(receivedPacket); +const unsigned char* dataAt = reinterpret_cast(receivedPacket.data()) + numBytesPacketHeader; + +uint16_t numSequenceNumbers = (*(uint16_t*)dataAt); +dataAt += sizeof(uint16_t); + +// read sequence numbers +QList sequenceNumbers; +for (int i = 0; i < numSequenceNumbers; i++) { + sequenceNumbers.append(*(OCTREE_PACKET_SEQUENCE*)dataAt); + dataAt += sizeof(OCTREE_PACKET_SEQUENCE); +} + +OctreeQueryNode* nodeData = (OctreeQueryNode*)matchingNode->getLinkedData(); // move this or something +nodeData->addSequenceNumbersToResend(sequenceNumbers); + + + } else if (packetType == PacketTypeJurisdictionRequest) { _jurisdictionSender->queueReceivedPacket(matchingNode, receivedPacket); } else if (_octreeInboundPacketProcessor && getOctree()->handlesEditPacketType(packetType)) { diff --git a/assignment-client/src/octree/SentPacketHistory.cpp b/assignment-client/src/octree/SentPacketHistory.cpp new file mode 100644 index 0000000000..0de163a23d --- /dev/null +++ b/assignment-client/src/octree/SentPacketHistory.cpp @@ -0,0 +1,45 @@ +// +// SentPacketHistory.cpp +// assignement-client/src/octree +// +// Created by Yixin Wang on 6/5/2014 +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "SentPacketHistory.h" + +SentPacketHistory::SentPacketHistory(int size) + : _sentPackets(size), + _newestPacketAt(0), + _numExistingPackets(0), + _newestSequenceNumber(0) +{ +} + +void SentPacketHistory::packetSent(OCTREE_PACKET_SEQUENCE sequenceNumber, const QByteArray& packet) { + _newestSequenceNumber = sequenceNumber; + + // increment _newestPacketAt cyclically, insert new packet there + _newestPacketAt = (_newestPacketAt == _sentPackets.size() - 1) ? 0 : _newestPacketAt + 1; + _sentPackets[_newestPacketAt] = packet; + + if (_numExistingPackets < _sentPackets.size()) { + _numExistingPackets++; + } +} + + +const QByteArray* SentPacketHistory::getPacket(OCTREE_PACKET_SEQUENCE sequenceNumber) const { + + OCTREE_PACKET_SEQUENCE seqDiff = _newestSequenceNumber - sequenceNumber; + if (!(seqDiff >= 0 && seqDiff < _numExistingPackets)) { + return NULL; + } + + int packetAt = _newestPacketAt - seqDiff; + if (packetAt < 0) { packetAt += _sentPackets.size(); } + + return &_sentPackets.at(packetAt); +} \ No newline at end of file diff --git a/assignment-client/src/octree/SentPacketHistory.h b/assignment-client/src/octree/SentPacketHistory.h new file mode 100644 index 0000000000..cbc50bc73c --- /dev/null +++ b/assignment-client/src/octree/SentPacketHistory.h @@ -0,0 +1,36 @@ +// +// SentPacketHistory.h +// assignement-client/src/octree +// +// Created by Yixin Wang on 6/5/2014 +// +// 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_SentPacketHistory_h +#define hifi_SentPacketHistory_h + +#include +#include + +#include "OctreePacketData.h" + +class SentPacketHistory { + +public: + SentPacketHistory(int size); + + void packetSent(OCTREE_PACKET_SEQUENCE sequenceNumber, const QByteArray& packet); + const QByteArray* getPacket(OCTREE_PACKET_SEQUENCE sequenceNumber) const; + +private: + + QVector _sentPackets; // circular buffer + int _newestPacketAt; + int _numExistingPackets; + + OCTREE_PACKET_SEQUENCE _newestSequenceNumber; +}; + +#endif diff --git a/assignment-client/src/particles/ParticleServer.cpp b/assignment-client/src/particles/ParticleServer.cpp index 1dd65f11f3..e7a0f75dfd 100644 --- a/assignment-client/src/particles/ParticleServer.cpp +++ b/assignment-client/src/particles/ParticleServer.cpp @@ -106,7 +106,7 @@ int ParticleServer::sendSpecialPacket(OctreeQueryNode* queryNode, const SharedNo //qDebug() << "sending PacketType_PARTICLE_ERASE packetLength:" << packetLength; NodeList::getInstance()->writeDatagram((char*) outputBuffer, packetLength, SharedNodePointer(node)); - queryNode->incrementSequenceNumber(); + queryNode->packetSent(outputBuffer, packetLength); } nodeData->setLastDeletedParticlesSentAt(deletePacketSentAt); diff --git a/assignment-client/src/voxels/VoxelServer.cpp b/assignment-client/src/voxels/VoxelServer.cpp index 8f4a8bab36..34b01f529a 100644 --- a/assignment-client/src/voxels/VoxelServer.cpp +++ b/assignment-client/src/voxels/VoxelServer.cpp @@ -75,7 +75,7 @@ int VoxelServer::sendSpecialPacket(OctreeQueryNode* queryNode, const SharedNodeP } NodeList::getInstance()->writeDatagram((char*) _tempOutputBuffer, envPacketLength, SharedNodePointer(node)); - queryNode->incrementSequenceNumber(); + queryNode->packetSent(_tempOutputBuffer, envPacketLength); return envPacketLength; } diff --git a/libraries/networking/src/PacketHeaders.h b/libraries/networking/src/PacketHeaders.h index 9c764f9f02..a73ffe8564 100644 --- a/libraries/networking/src/PacketHeaders.h +++ b/libraries/networking/src/PacketHeaders.h @@ -66,6 +66,7 @@ enum PacketType { PacketTypeModelAddOrEdit, PacketTypeModelErase, PacketTypeModelAddResponse, + PacketTypeOctreeDataNack }; typedef char PacketVersion; From 5461a06e992b2b7dd5bb2e1aff16a347a87963b6 Mon Sep 17 00:00:00 2001 From: wangyix Date: Fri, 6 Jun 2014 09:33:14 -0700 Subject: [PATCH 14/52] completed code to resend nacked packets on AC --- .../src/octree/OctreeQueryNode.cpp | 16 ++++++++-------- .../src/octree/OctreeQueryNode.h | 8 ++++---- .../src/octree/OctreeSendThread.cpp | 19 ++++++++++--------- assignment-client/src/octree/OctreeServer.cpp | 5 ++++- 4 files changed, 26 insertions(+), 22 deletions(-) diff --git a/assignment-client/src/octree/OctreeQueryNode.cpp b/assignment-client/src/octree/OctreeQueryNode.cpp index e0ca6a4f1e..208be5951b 100644 --- a/assignment-client/src/octree/OctreeQueryNode.cpp +++ b/assignment-client/src/octree/OctreeQueryNode.cpp @@ -364,7 +364,7 @@ void OctreeQueryNode::dumpOutOfView() { } } -void OctreeQueryNode::packetSent() { +void OctreeQueryNode::octreePacketSent() { packetSent(_octreePacket, getPacketLength()); } @@ -379,18 +379,18 @@ void OctreeQueryNode::packetSent(const QByteArray& packet) { void OctreeQueryNode::addSequenceNumbersToResend(const QList& sequenceNumbers) { - _sequenceNumbersToResend.append(sequenceNumbers); + _nackedSequenceNumbers.append(sequenceNumbers); } -bool OctreeQueryNode::hasNextPacketToResend() const { - return !_sequenceNumbersToResend.isEmpty(); +bool OctreeQueryNode::hasNextNackedPacket() const { + return !_nackedSequenceNumbers.isEmpty(); } -const QByteArray* OctreeQueryNode::getNextPacketToResend() { +const QByteArray* OctreeQueryNode::getNextNackedPacket() { - if (!_sequenceNumbersToResend.isEmpty()) { - const QByteArray* nextPacket = _sentPacketHistory.getPacket(_sequenceNumbersToResend.first()); - _sequenceNumbersToResend.pop_front(); + if (!_nackedSequenceNumbers.isEmpty()) { + const QByteArray* nextPacket = _sentPacketHistory.getPacket(_nackedSequenceNumbers.first()); + _nackedSequenceNumbers.pop_front(); return nextPacket; // could be null } return NULL; diff --git a/assignment-client/src/octree/OctreeQueryNode.h b/assignment-client/src/octree/OctreeQueryNode.h index 4a2355f7cc..e1707cc899 100644 --- a/assignment-client/src/octree/OctreeQueryNode.h +++ b/assignment-client/src/octree/OctreeQueryNode.h @@ -103,15 +103,15 @@ public: void forceNodeShutdown(); bool isShuttingDown() const { return _isShuttingDown; } - void packetSent(); + void octreePacketSent(); void packetSent(unsigned char* packet, int packetLength); void packetSent(const QByteArray& packet); OCTREE_PACKET_SEQUENCE getSequenceNumber() const { return _sequenceNumber; } void addSequenceNumbersToResend(const QList& sequenceNumbers); - bool hasNextPacketToResend() const; - const QByteArray* getNextPacketToResend(); + bool hasNextNackedPacket() const; + const QByteArray* getNextNackedPacket(); private slots: void sendThreadFinished(); @@ -157,7 +157,7 @@ private: bool _isShuttingDown; SentPacketHistory _sentPacketHistory; -QQueue _sequenceNumbersToResend; +QQueue _nackedSequenceNumbers; }; #endif // hifi_OctreeQueryNode_h diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index 5767f2623b..befea80380 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -85,6 +85,7 @@ bool OctreeSendThread::process() { if (nodeData && !nodeData->isShuttingDown()) { bool viewFrustumChanged = nodeData->updateCurrentViewFrustum(); packetDistributor(nodeData, viewFrustumChanged); +resendNackedPackets(nodeData); } } } @@ -274,7 +275,7 @@ int OctreeSendThread::handlePacketSend(OctreeQueryNode* nodeData, int& trueBytes trueBytesSent += nodeData->getPacketLength(); truePacketsSent++; packetsSent++; - nodeData->packetSent(); + nodeData->octreePacketSent(); nodeData->resetOctreePacket(); } @@ -287,11 +288,14 @@ int OctreeSendThread::handlePacketSend(OctreeQueryNode* nodeData, int& trueBytes int OctreeSendThread::resendNackedPackets(OctreeQueryNode* nodeData) { + const int maxPacketsSent = 10; + int packetsSent = 0; const QByteArray* packet; - while (nodeData->hasNextPacketToResend()) { - packet = nodeData->getNextPacketToResend(); + while (nodeData->hasNextNackedPacket() && packetsSent < maxPacketsSent) { + packet = nodeData->getNextNackedPacket(); + // packet will be NULL if it's not in nodeData's packet history if (packet) { NodeList::getInstance()->writeDatagram(*packet, _node); packetsSent++; @@ -302,7 +306,9 @@ int OctreeSendThread::resendNackedPackets(OctreeQueryNode* nodeData) { _totalWastedBytes += MAX_PACKET_SIZE - packet->size(); // ??? } } - + +printf("\t\t re-sent %d packets!\n", packetsSent); + return packetsSent; } @@ -310,11 +316,6 @@ int OctreeSendThread::resendNackedPackets(OctreeQueryNode* nodeData) { - - - - - /// Version of voxel distributor that sends the deepest LOD level at once int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrustumChanged) { diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index f60f0fc2d5..46eb7aac16 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -861,8 +861,11 @@ dataAt += sizeof(uint16_t); // read sequence numbers QList sequenceNumbers; for (int i = 0; i < numSequenceNumbers; i++) { - sequenceNumbers.append(*(OCTREE_PACKET_SEQUENCE*)dataAt); + OCTREE_PACKET_SEQUENCE sequenceNumber = (*(OCTREE_PACKET_SEQUENCE*)dataAt); + sequenceNumbers.append(sequenceNumber); dataAt += sizeof(OCTREE_PACKET_SEQUENCE); + +printf("\t\t\t nacked packet: seq = %d\n", sequenceNumber); } OctreeQueryNode* nodeData = (OctreeQueryNode*)matchingNode->getLinkedData(); // move this or something From 7da091d2b41010dcb8d81189ecf2df0caa123f64 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 6 Jun 2014 10:15:09 -0700 Subject: [PATCH 15/52] initial hooks for stereo audio --- interface/src/Audio.cpp | 283 ++++++++++-------- interface/src/Audio.h | 2 + interface/src/Menu.cpp | 2 + interface/src/Menu.h | 1 + .../audio/src/PositionalAudioRingBuffer.cpp | 7 +- .../audio/src/PositionalAudioRingBuffer.h | 3 +- libraries/networking/src/PacketHeaders.cpp | 3 + 7 files changed, 169 insertions(+), 132 deletions(-) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 50ab720450..6d672b736d 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -68,6 +68,7 @@ Audio::Audio(int16_t initialJitterBufferSamples, QObject* parent) : _proceduralOutputDevice(NULL), _inputRingBuffer(0), _ringBuffer(NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL), + _isStereoInput(false), _averagedLatency(0.0), _measuredJitter(0), _jitterBufferSamples(initialJitterBufferSamples), @@ -405,12 +406,12 @@ bool Audio::switchOutputToAudioDevice(const QString& outputDeviceName) { } void Audio::handleAudioInput() { - static char monoAudioDataPacket[MAX_PACKET_SIZE]; + static char audioDataPacket[MAX_PACKET_SIZE]; static int numBytesPacketHeader = numBytesForPacketHeaderGivenPacketType(PacketTypeMicrophoneAudioNoEcho); static int leadingBytes = numBytesPacketHeader + sizeof(glm::vec3) + sizeof(glm::quat); - static int16_t* monoAudioSamples = (int16_t*) (monoAudioDataPacket + leadingBytes); + static int16_t* networkAudioSamples = (int16_t*) (audioDataPacket + leadingBytes); float inputToNetworkInputRatio = calculateDeviceToNetworkInputRatio(_numInputCallbackBytes); @@ -452,125 +453,130 @@ void Audio::handleAudioInput() { int16_t* inputAudioSamples = new int16_t[inputSamplesRequired]; _inputRingBuffer.readSamples(inputAudioSamples, inputSamplesRequired); + + int numNetworkBytes = _isStereoInput ? NETWORK_BUFFER_LENGTH_BYTES_STEREO : NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL; + int numNetworkSamples = _isStereoInput ? NETWORK_BUFFER_LENGTH_SAMPLES_STEREO : NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL; // zero out the monoAudioSamples array and the locally injected audio - memset(monoAudioSamples, 0, NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL); + memset(networkAudioSamples, 0, numNetworkBytes); if (!_muted) { // we aren't muted, downsample the input audio - linearResampling((int16_t*) inputAudioSamples, - monoAudioSamples, - inputSamplesRequired, - NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL, + linearResampling((int16_t*) inputAudioSamples, networkAudioSamples, + inputSamplesRequired, numNetworkSamples, _inputFormat, _desiredInputFormat); - // - // Impose Noise Gate - // - // The Noise Gate is used to reject constant background noise by measuring the noise - // floor observed at the microphone and then opening the 'gate' to allow microphone - // signals to be transmitted when the microphone samples average level exceeds a multiple - // of the noise floor. - // - // NOISE_GATE_HEIGHT: How loud you have to speak relative to noise background to open the gate. - // Make this value lower for more sensitivity and less rejection of noise. - // NOISE_GATE_WIDTH: The number of samples in an audio frame for which the height must be exceeded - // to open the gate. - // NOISE_GATE_CLOSE_FRAME_DELAY: Once the noise is below the gate height for the frame, how many frames - // will we wait before closing the gate. - // NOISE_GATE_FRAMES_TO_AVERAGE: How many audio frames should we average together to compute noise floor. - // More means better rejection but also can reject continuous things like singing. - // NUMBER_OF_NOISE_SAMPLE_FRAMES: How often should we re-evaluate the noise floor? - - - float loudness = 0; - float thisSample = 0; - int samplesOverNoiseGate = 0; - - const float NOISE_GATE_HEIGHT = 7.0f; - const int NOISE_GATE_WIDTH = 5; - const int NOISE_GATE_CLOSE_FRAME_DELAY = 5; - const int NOISE_GATE_FRAMES_TO_AVERAGE = 5; - const float DC_OFFSET_AVERAGING = 0.99f; - const float CLIPPING_THRESHOLD = 0.90f; - - // - // Check clipping, adjust DC offset, and check if should open noise gate - // - float measuredDcOffset = 0.0f; - // Increment the time since the last clip - if (_timeSinceLastClip >= 0.0f) { - _timeSinceLastClip += (float) NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL / (float) SAMPLE_RATE; - } - - for (int i = 0; i < NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL; i++) { - measuredDcOffset += monoAudioSamples[i]; - monoAudioSamples[i] -= (int16_t) _dcOffset; - thisSample = fabsf(monoAudioSamples[i]); - if (thisSample >= (32767.0f * CLIPPING_THRESHOLD)) { - _timeSinceLastClip = 0.0f; + // only impose the noise gate and perform tone injection if we sending mono audio + if (!_isStereoInput) { + + // + // Impose Noise Gate + // + // The Noise Gate is used to reject constant background noise by measuring the noise + // floor observed at the microphone and then opening the 'gate' to allow microphone + // signals to be transmitted when the microphone samples average level exceeds a multiple + // of the noise floor. + // + // NOISE_GATE_HEIGHT: How loud you have to speak relative to noise background to open the gate. + // Make this value lower for more sensitivity and less rejection of noise. + // NOISE_GATE_WIDTH: The number of samples in an audio frame for which the height must be exceeded + // to open the gate. + // NOISE_GATE_CLOSE_FRAME_DELAY: Once the noise is below the gate height for the frame, how many frames + // will we wait before closing the gate. + // NOISE_GATE_FRAMES_TO_AVERAGE: How many audio frames should we average together to compute noise floor. + // More means better rejection but also can reject continuous things like singing. + // NUMBER_OF_NOISE_SAMPLE_FRAMES: How often should we re-evaluate the noise floor? + + + float loudness = 0; + float thisSample = 0; + int samplesOverNoiseGate = 0; + + const float NOISE_GATE_HEIGHT = 7.0f; + const int NOISE_GATE_WIDTH = 5; + const int NOISE_GATE_CLOSE_FRAME_DELAY = 5; + const int NOISE_GATE_FRAMES_TO_AVERAGE = 5; + const float DC_OFFSET_AVERAGING = 0.99f; + const float CLIPPING_THRESHOLD = 0.90f; + + // + // Check clipping, adjust DC offset, and check if should open noise gate + // + float measuredDcOffset = 0.0f; + // Increment the time since the last clip + if (_timeSinceLastClip >= 0.0f) { + _timeSinceLastClip += (float) NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL / (float) SAMPLE_RATE; } - loudness += thisSample; - // Noise Reduction: Count peaks above the average loudness - if (_noiseGateEnabled && (thisSample > (_noiseGateMeasuredFloor * NOISE_GATE_HEIGHT))) { - samplesOverNoiseGate++; - } - } - - measuredDcOffset /= NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL; - if (_dcOffset == 0.0f) { - // On first frame, copy over measured offset - _dcOffset = measuredDcOffset; - } else { - _dcOffset = DC_OFFSET_AVERAGING * _dcOffset + (1.0f - DC_OFFSET_AVERAGING) * measuredDcOffset; - } - - // Add tone injection if enabled - const float TONE_FREQ = 220.0f / SAMPLE_RATE * TWO_PI; - const float QUARTER_VOLUME = 8192.0f; - if (_toneInjectionEnabled) { - loudness = 0.0f; + for (int i = 0; i < NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL; i++) { - monoAudioSamples[i] = QUARTER_VOLUME * sinf(TONE_FREQ * (float)(i + _proceduralEffectSample)); - loudness += fabsf(monoAudioSamples[i]); - } - } - _lastInputLoudness = fabs(loudness / NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL); - - // If Noise Gate is enabled, check and turn the gate on and off - if (!_toneInjectionEnabled && _noiseGateEnabled) { - float averageOfAllSampleFrames = 0.0f; - _noiseSampleFrames[_noiseGateSampleCounter++] = _lastInputLoudness; - if (_noiseGateSampleCounter == NUMBER_OF_NOISE_SAMPLE_FRAMES) { - float smallestSample = FLT_MAX; - for (int i = 0; i <= NUMBER_OF_NOISE_SAMPLE_FRAMES - NOISE_GATE_FRAMES_TO_AVERAGE; i += NOISE_GATE_FRAMES_TO_AVERAGE) { - float thisAverage = 0.0f; - for (int j = i; j < i + NOISE_GATE_FRAMES_TO_AVERAGE; j++) { - thisAverage += _noiseSampleFrames[j]; - averageOfAllSampleFrames += _noiseSampleFrames[j]; - } - thisAverage /= NOISE_GATE_FRAMES_TO_AVERAGE; - - if (thisAverage < smallestSample) { - smallestSample = thisAverage; - } + measuredDcOffset += networkAudioSamples[i]; + networkAudioSamples[i] -= (int16_t) _dcOffset; + thisSample = fabsf(networkAudioSamples[i]); + if (thisSample >= (32767.0f * CLIPPING_THRESHOLD)) { + _timeSinceLastClip = 0.0f; + } + loudness += thisSample; + // Noise Reduction: Count peaks above the average loudness + if (_noiseGateEnabled && (thisSample > (_noiseGateMeasuredFloor * NOISE_GATE_HEIGHT))) { + samplesOverNoiseGate++; } - averageOfAllSampleFrames /= NUMBER_OF_NOISE_SAMPLE_FRAMES; - _noiseGateMeasuredFloor = smallestSample; - _noiseGateSampleCounter = 0; - } - if (samplesOverNoiseGate > NOISE_GATE_WIDTH) { - _noiseGateOpen = true; - _noiseGateFramesToClose = NOISE_GATE_CLOSE_FRAME_DELAY; + + measuredDcOffset /= NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL; + if (_dcOffset == 0.0f) { + // On first frame, copy over measured offset + _dcOffset = measuredDcOffset; } else { - if (--_noiseGateFramesToClose == 0) { - _noiseGateOpen = false; + _dcOffset = DC_OFFSET_AVERAGING * _dcOffset + (1.0f - DC_OFFSET_AVERAGING) * measuredDcOffset; + } + + // Add tone injection if enabled + const float TONE_FREQ = 220.0f / SAMPLE_RATE * TWO_PI; + const float QUARTER_VOLUME = 8192.0f; + if (_toneInjectionEnabled) { + loudness = 0.0f; + for (int i = 0; i < NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL; i++) { + networkAudioSamples[i] = QUARTER_VOLUME * sinf(TONE_FREQ * (float)(i + _proceduralEffectSample)); + loudness += fabsf(networkAudioSamples[i]); } } - if (!_noiseGateOpen) { - memset(monoAudioSamples, 0, NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL); - _lastInputLoudness = 0; + _lastInputLoudness = fabs(loudness / NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL); + + // If Noise Gate is enabled, check and turn the gate on and off + if (!_toneInjectionEnabled && _noiseGateEnabled) { + float averageOfAllSampleFrames = 0.0f; + _noiseSampleFrames[_noiseGateSampleCounter++] = _lastInputLoudness; + if (_noiseGateSampleCounter == NUMBER_OF_NOISE_SAMPLE_FRAMES) { + float smallestSample = FLT_MAX; + for (int i = 0; i <= NUMBER_OF_NOISE_SAMPLE_FRAMES - NOISE_GATE_FRAMES_TO_AVERAGE; i += NOISE_GATE_FRAMES_TO_AVERAGE) { + float thisAverage = 0.0f; + for (int j = i; j < i + NOISE_GATE_FRAMES_TO_AVERAGE; j++) { + thisAverage += _noiseSampleFrames[j]; + averageOfAllSampleFrames += _noiseSampleFrames[j]; + } + thisAverage /= NOISE_GATE_FRAMES_TO_AVERAGE; + + if (thisAverage < smallestSample) { + smallestSample = thisAverage; + } + } + averageOfAllSampleFrames /= NUMBER_OF_NOISE_SAMPLE_FRAMES; + _noiseGateMeasuredFloor = smallestSample; + _noiseGateSampleCounter = 0; + + } + if (samplesOverNoiseGate > NOISE_GATE_WIDTH) { + _noiseGateOpen = true; + _noiseGateFramesToClose = NOISE_GATE_CLOSE_FRAME_DELAY; + } else { + if (--_noiseGateFramesToClose == 0) { + _noiseGateOpen = false; + } + } + if (!_noiseGateOpen) { + memset(networkAudioSamples, 0, NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL); + _lastInputLoudness = 0; + } } } } else { @@ -580,19 +586,19 @@ void Audio::handleAudioInput() { // at this point we have clean monoAudioSamples, which match our target output... // this is what we should send to our interested listeners - if (_processSpatialAudio && !_muted && _audioOutput) { - QByteArray monoInputData((char*)monoAudioSamples, NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL * sizeof(int16_t)); + if (_processSpatialAudio && !_muted && !_isStereoInput && _audioOutput) { + QByteArray monoInputData((char*)networkAudioSamples, NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL * sizeof(int16_t)); emit processLocalAudio(_spatialAudioStart, monoInputData, _desiredInputFormat); } - if (_proceduralAudioOutput) { - processProceduralAudio(monoAudioSamples, NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL); + if (!_isStereoInput && _proceduralAudioOutput) { + processProceduralAudio(networkAudioSamples, NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL); } - if (_scopeEnabled && !_scopeEnabledPause) { + if (!_isStereoInput && _scopeEnabled && !_scopeEnabledPause) { unsigned int numMonoAudioChannels = 1; unsigned int monoAudioChannel = 0; - addBufferToScope(_scopeInput, _scopeInputOffset, monoAudioSamples, monoAudioChannel, numMonoAudioChannels); + addBufferToScope(_scopeInput, _scopeInputOffset, networkAudioSamples, monoAudioChannel, numMonoAudioChannels); _scopeInputOffset += NETWORK_SAMPLES_PER_FRAME; _scopeInputOffset %= _samplesPerScope; } @@ -615,7 +621,7 @@ void Audio::handleAudioInput() { packetType = PacketTypeSilentAudioFrame; // we need to indicate how many silent samples this is to the audio mixer - monoAudioSamples[0] = NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL; + networkAudioSamples[0] = NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL; numAudioBytes = sizeof(int16_t); } else { @@ -628,7 +634,7 @@ void Audio::handleAudioInput() { } } - char* currentPacketPtr = monoAudioDataPacket + populatePacketHeader(monoAudioDataPacket, packetType); + char* currentPacketPtr = audioDataPacket + populatePacketHeader(audioDataPacket, packetType); // memcpy the three float positions memcpy(currentPacketPtr, &headPosition, sizeof(headPosition)); @@ -638,7 +644,7 @@ void Audio::handleAudioInput() { memcpy(currentPacketPtr, &headOrientation, sizeof(headOrientation)); currentPacketPtr += sizeof(headOrientation); - nodeList->writeDatagram(monoAudioDataPacket, numAudioBytes + leadingBytes, audioMixer); + nodeList->writeDatagram(audioDataPacket, numAudioBytes + leadingBytes, audioMixer); Application::getInstance()->getBandwidthMeter()->outputStream(BandwidthMeter::AUDIO) .updateValue(numAudioBytes + leadingBytes); @@ -761,6 +767,24 @@ void Audio::toggleAudioNoiseReduction() { _noiseGateEnabled = !_noiseGateEnabled; } +void Audio::toggleStereoInput() { + int oldChannelCount = _desiredInputFormat.channelCount(); + QAction* stereoAudioOption = Menu::getInstance()->getActionForOption(MenuOption::StereoAudio); + + if (stereoAudioOption->isChecked()) { + _desiredInputFormat.setChannelCount(2); + _isStereoInput = true; + } else { + _desiredInputFormat.setChannelCount(1); + _isStereoInput = false; + } + + if (oldChannelCount != _desiredInputFormat.channelCount()) { + // change in channel count for desired input format, restart the input device + switchInputToAudioDevice(_inputAudioDeviceName); + } +} + void Audio::processReceivedAudio(const QByteArray& audioByteArray) { _ringBuffer.parseData(audioByteArray); @@ -1300,18 +1324,21 @@ bool Audio::switchInputToAudioDevice(const QAudioDeviceInfo& inputDeviceInfo) { if (adjustedFormatForAudioDevice(inputDeviceInfo, _desiredInputFormat, _inputFormat)) { qDebug() << "The format to be used for audio input is" << _inputFormat; - - _audioInput = new QAudioInput(inputDeviceInfo, _inputFormat, this); - _numInputCallbackBytes = calculateNumberOfInputCallbackBytes(_inputFormat); - _audioInput->setBufferSize(_numInputCallbackBytes); - - // how do we want to handle input working, but output not working? - int numFrameSamples = calculateNumberOfFrameSamples(_numInputCallbackBytes); - _inputRingBuffer.resizeForFrameSize(numFrameSamples); - _inputDevice = _audioInput->start(); - connect(_inputDevice, SIGNAL(readyRead()), this, SLOT(handleAudioInput())); - - supportedFormat = true; + + // if the user wants stereo but this device can't provide then bail + if (!_isStereoInput || _inputFormat.channelCount() == 2) { + _audioInput = new QAudioInput(inputDeviceInfo, _inputFormat, this); + _numInputCallbackBytes = calculateNumberOfInputCallbackBytes(_inputFormat); + _audioInput->setBufferSize(_numInputCallbackBytes); + + // how do we want to handle input working, but output not working? + int numFrameSamples = calculateNumberOfFrameSamples(_numInputCallbackBytes); + _inputRingBuffer.resizeForFrameSize(numFrameSamples); + _inputDevice = _audioInput->start(); + connect(_inputDevice, SIGNAL(readyRead()), this, SLOT(handleAudioInput())); + + supportedFormat = true; + } } } return supportedFormat; diff --git a/interface/src/Audio.h b/interface/src/Audio.h index 79f0f84ff5..74fc373cb0 100644 --- a/interface/src/Audio.h +++ b/interface/src/Audio.h @@ -85,6 +85,7 @@ public slots: void toggleScope(); void toggleScopePause(); void toggleAudioSpatialProcessing(); + void toggleStereoInput(); void selectAudioScopeFiveFrames(); void selectAudioScopeTwentyFrames(); void selectAudioScopeFiftyFrames(); @@ -127,6 +128,7 @@ private: QIODevice* _proceduralOutputDevice; AudioRingBuffer _inputRingBuffer; AudioRingBuffer _ringBuffer; + bool _isStereoInput; QString _inputAudioDeviceName; QString _outputAudioDeviceName; diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 5d9cd1f1c4..9ab47cdeda 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -432,6 +432,8 @@ Menu::Menu() : SLOT(toggleAudioNoiseReduction())); addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::EchoServerAudio); addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::EchoLocalAudio); + addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::StereoAudio, 0, false, + appInstance->getAudio(), SLOT(toggleStereoInput())); addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::MuteAudio, Qt::CTRL | Qt::Key_M, false, diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 6bc9adef05..f9af80119b 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -402,6 +402,7 @@ namespace MenuOption { const QString StandOnNearbyFloors = "Stand on nearby floors"; const QString Stars = "Stars"; const QString Stats = "Stats"; + const QString StereoAudio = "Stereo Audio"; const QString StopAllScripts = "Stop All Scripts"; const QString SuppressShortTimings = "Suppress Timings Less than 10ms"; const QString TestPing = "Test Ping"; diff --git a/libraries/audio/src/PositionalAudioRingBuffer.cpp b/libraries/audio/src/PositionalAudioRingBuffer.cpp index 6fc16c57a9..0a3d2d0c16 100644 --- a/libraries/audio/src/PositionalAudioRingBuffer.cpp +++ b/libraries/audio/src/PositionalAudioRingBuffer.cpp @@ -20,14 +20,15 @@ #include "PositionalAudioRingBuffer.h" -PositionalAudioRingBuffer::PositionalAudioRingBuffer(PositionalAudioRingBuffer::Type type) : - AudioRingBuffer(NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL), +PositionalAudioRingBuffer::PositionalAudioRingBuffer(PositionalAudioRingBuffer::Type type, bool isStereo) : + AudioRingBuffer(isStereo ? NETWORK_BUFFER_LENGTH_SAMPLES_STEREO : NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL), _type(type), _position(0.0f, 0.0f, 0.0f), _orientation(0.0f, 0.0f, 0.0f, 0.0f), _willBeAddedToMix(false), _shouldLoopbackForNode(false), - _shouldOutputStarveDebug(true) + _shouldOutputStarveDebug(true), + _isStereo(isStereo) { } diff --git a/libraries/audio/src/PositionalAudioRingBuffer.h b/libraries/audio/src/PositionalAudioRingBuffer.h index b130a9b216..1864271d5f 100644 --- a/libraries/audio/src/PositionalAudioRingBuffer.h +++ b/libraries/audio/src/PositionalAudioRingBuffer.h @@ -24,7 +24,7 @@ public: Injector }; - PositionalAudioRingBuffer(PositionalAudioRingBuffer::Type type); + PositionalAudioRingBuffer(PositionalAudioRingBuffer::Type type, bool isStereo = false); ~PositionalAudioRingBuffer(); int parseData(const QByteArray& packet); @@ -56,6 +56,7 @@ protected: bool _willBeAddedToMix; bool _shouldLoopbackForNode; bool _shouldOutputStarveDebug; + bool _isStereo; float _nextOutputTrailingLoudness; }; diff --git a/libraries/networking/src/PacketHeaders.cpp b/libraries/networking/src/PacketHeaders.cpp index c56dba9cf1..751c6f45b2 100644 --- a/libraries/networking/src/PacketHeaders.cpp +++ b/libraries/networking/src/PacketHeaders.cpp @@ -47,6 +47,9 @@ int packArithmeticallyCodedValue(int value, char* destination) { PacketVersion versionForPacketType(PacketType type) { switch (type) { + case PacketTypeMicrophoneAudioNoEcho: + case PacketTypeMicrophoneAudioWithEcho: + return 1; case PacketTypeAvatarData: return 3; case PacketTypeAvatarIdentity: From 4209c1102f56420a0024baa1ec997b008f3a329e Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 6 Jun 2014 10:26:08 -0700 Subject: [PATCH 16/52] Revert "Models.addModel now returns a more accurate modelID" This reverts commit 150477eea44d0438137333499fcda498072c76ea. --- libraries/models/src/ModelItem.cpp | 31 ++++++++++++++----- libraries/models/src/ModelItem.h | 1 - .../models/src/ModelsScriptingInterface.cpp | 3 +- 3 files changed, 24 insertions(+), 11 deletions(-) diff --git a/libraries/models/src/ModelItem.cpp b/libraries/models/src/ModelItem.cpp index 810129a81f..b6f4fe6c1d 100644 --- a/libraries/models/src/ModelItem.cpp +++ b/libraries/models/src/ModelItem.cpp @@ -47,12 +47,6 @@ uint32_t ModelItem::getNextCreatorTokenID() { return creatorTokenID; } -uint32_t ModelItem::getNextModelItemID() { - uint32_t modelID = _nextID; - _nextID++; - return modelID; -} - void ModelItem::handleAddModelResponse(const QByteArray& packet) { const unsigned char* dataAt = reinterpret_cast(packet.data()); int numBytesPacketHeader = numBytesForPacketHeader(packet); @@ -76,10 +70,31 @@ ModelItem::ModelItem() { } ModelItem::ModelItem(const ModelItemID& modelItemID, const ModelItemProperties& properties) { + _id = modelItemID.id; _creatorTokenID = modelItemID.creatorTokenID; + + // init values with defaults before calling setProperties + uint64_t now = usecTimestampNow(); + _lastEdited = now; + _lastUpdated = now; + + _position = glm::vec3(0,0,0); + _radius = 0; + rgbColor noColor = { 0, 0, 0 }; + memcpy(_color, noColor, sizeof(_color)); + _shouldDie = false; + _modelURL = MODEL_DEFAULT_MODEL_URL; + _modelRotation = MODEL_DEFAULT_MODEL_ROTATION; - rgbColor defaultColor = { 0, 0, 0 }; - init(glm::vec3(), 0.0f, defaultColor, modelItemID.id); + // animation related + _animationURL = MODEL_DEFAULT_ANIMATION_URL; + _animationIsPlaying = false; + _animationFrameIndex = 0.0f; + _animationFPS = MODEL_DEFAULT_ANIMATION_FPS; + _glowLevel = 0.0f; + + _jointMappingCompleted = false; + _lastAnimated = now; setProperties(properties); } diff --git a/libraries/models/src/ModelItem.h b/libraries/models/src/ModelItem.h index 563d394419..9a558f2ef4 100644 --- a/libraries/models/src/ModelItem.h +++ b/libraries/models/src/ModelItem.h @@ -276,7 +276,6 @@ public: // these methods allow you to create models, and later edit them. static uint32_t getIDfromCreatorTokenID(uint32_t creatorTokenID); static uint32_t getNextCreatorTokenID(); - static uint32_t getNextModelItemID(); static void handleAddModelResponse(const QByteArray& packet); void mapJoints(const QStringList& modelJointNames); diff --git a/libraries/models/src/ModelsScriptingInterface.cpp b/libraries/models/src/ModelsScriptingInterface.cpp index f4cbf14086..7e08571fe5 100644 --- a/libraries/models/src/ModelsScriptingInterface.cpp +++ b/libraries/models/src/ModelsScriptingInterface.cpp @@ -28,9 +28,8 @@ ModelItemID ModelsScriptingInterface::addModel(const ModelItemProperties& proper // The application will keep track of creatorTokenID uint32_t creatorTokenID = ModelItem::getNextCreatorTokenID(); - uint32_t modelID = ModelItem::getNextModelItemID(); - ModelItemID id(modelID, creatorTokenID, false ); + ModelItemID id(NEW_MODEL, creatorTokenID, false ); // queue the packet queueModelMessage(PacketTypeModelAddOrEdit, id, properties); From 681ce247d6230ffe561dcfe8cda2eaefa3c884c0 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 6 Jun 2014 10:27:59 -0700 Subject: [PATCH 17/52] tweak resample to handle 48 to 24 stereo, add stereo/mono byte --- interface/src/Audio.cpp | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 6d672b736d..1575aa524f 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -290,20 +290,27 @@ void linearResampling(int16_t* sourceSamples, int16_t* destinationSamples, if (sourceToDestinationFactor >= 2) { // we need to downsample from 48 to 24 // for now this only supports a mono output - this would be the case for audio input - - for (unsigned int i = sourceAudioFormat.channelCount(); i < numSourceSamples; i += 2 * sourceAudioFormat.channelCount()) { - if (i + (sourceAudioFormat.channelCount()) >= numSourceSamples) { - destinationSamples[(i - sourceAudioFormat.channelCount()) / (int) sourceToDestinationFactor] = + if (destinationAudioFormat.channelCount() == 1) { + for (unsigned int i = sourceAudioFormat.channelCount(); i < numSourceSamples; i += 2 * sourceAudioFormat.channelCount()) { + if (i + (sourceAudioFormat.channelCount()) >= numSourceSamples) { + destinationSamples[(i - sourceAudioFormat.channelCount()) / (int) sourceToDestinationFactor] = (sourceSamples[i - sourceAudioFormat.channelCount()] / 2) + (sourceSamples[i] / 2); - } else { - destinationSamples[(i - sourceAudioFormat.channelCount()) / (int) sourceToDestinationFactor] = + } else { + destinationSamples[(i - sourceAudioFormat.channelCount()) / (int) sourceToDestinationFactor] = (sourceSamples[i - sourceAudioFormat.channelCount()] / 4) + (sourceSamples[i] / 2) + (sourceSamples[i + sourceAudioFormat.channelCount()] / 4); + } + } + } else { + // this is a 48 to 24 resampling but both source and destination are two channels + // squish two samples into one in each channel + for (int i = 0; i < numSourceSamples; i += 2) { + destinationSamples[i / 2] = (sourceSamples[i] / 2) + (sourceSamples[i + 2] / 2); + destinationSamples[(i / 2) + 1] = (sourceSamples[i + 1] / 2) + (sourceSamples[i + 3] / 2); } } - } else { if (sourceAudioFormat.sampleRate() == destinationAudioFormat.sampleRate()) { // mono to stereo, same sample rate @@ -409,7 +416,7 @@ void Audio::handleAudioInput() { static char audioDataPacket[MAX_PACKET_SIZE]; static int numBytesPacketHeader = numBytesForPacketHeaderGivenPacketType(PacketTypeMicrophoneAudioNoEcho); - static int leadingBytes = numBytesPacketHeader + sizeof(glm::vec3) + sizeof(glm::quat); + static int leadingBytes = numBytesPacketHeader + sizeof(glm::vec3) + sizeof(glm::quat) + sizeof(quint8); static int16_t* networkAudioSamples = (int16_t*) (audioDataPacket + leadingBytes); @@ -610,9 +617,7 @@ void Audio::handleAudioInput() { MyAvatar* interfaceAvatar = Application::getInstance()->getAvatar(); glm::vec3 headPosition = interfaceAvatar->getHead()->getPosition(); glm::quat headOrientation = interfaceAvatar->getHead()->getFinalOrientation(); - - // we need the amount of bytes in the buffer + 1 for type - // + 12 for 3 floats for position + float for bearing + 1 attenuation byte + quint8 isStereo = _isStereoInput ? 1 : 0; int numAudioBytes = 0; @@ -621,7 +626,7 @@ void Audio::handleAudioInput() { packetType = PacketTypeSilentAudioFrame; // we need to indicate how many silent samples this is to the audio mixer - networkAudioSamples[0] = NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL; + audioDataPacket[0] = NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL; numAudioBytes = sizeof(int16_t); } else { @@ -644,6 +649,9 @@ void Audio::handleAudioInput() { memcpy(currentPacketPtr, &headOrientation, sizeof(headOrientation)); currentPacketPtr += sizeof(headOrientation); + // set the mono/stereo byte + *currentPacketPtr++ = isStereo; + nodeList->writeDatagram(audioDataPacket, numAudioBytes + leadingBytes, audioMixer); Application::getInstance()->getBandwidthMeter()->outputStream(BandwidthMeter::AUDIO) From ae2f6a3cb676294457beae372a0bc7bb9dc1728f Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 6 Jun 2014 10:55:04 -0700 Subject: [PATCH 18/52] complete piping of stereo audio through mixer --- assignment-client/src/audio/AudioMixer.cpp | 242 ++++++++++-------- .../src/audio/AudioMixerClientData.cpp | 14 +- .../src/audio/AudioMixerClientData.h | 4 +- .../src/audio/AvatarAudioRingBuffer.cpp | 4 +- .../src/audio/AvatarAudioRingBuffer.h | 2 +- interface/src/Audio.cpp | 6 +- .../audio/src/PositionalAudioRingBuffer.cpp | 3 + .../audio/src/PositionalAudioRingBuffer.h | 2 + 8 files changed, 160 insertions(+), 117 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 3acd783bb0..f8cfb3140c 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -173,134 +173,160 @@ void AudioMixer::addBufferToMixForListeningNodeWithBuffer(PositionalAudioRingBuf weakChannelAmplitudeRatio = 1 - (PHASE_AMPLITUDE_RATIO_AT_90 * sinRatio); } } - - // if the bearing relative angle to source is > 0 then the delayed channel is the right one - int delayedChannelOffset = (bearingRelativeAngleToSource > 0.0f) ? 1 : 0; - int goodChannelOffset = delayedChannelOffset == 0 ? 1 : 0; const int16_t* nextOutputStart = bufferToAdd->getNextOutput(); - - const int16_t* bufferStart = bufferToAdd->getBuffer(); - int ringBufferSampleCapacity = bufferToAdd->getSampleCapacity(); - - int16_t correctBufferSample[2], delayBufferSample[2]; - int delayedChannelIndex = 0; - const int SINGLE_STEREO_OFFSET = 2; - - for (int s = 0; s < NETWORK_BUFFER_LENGTH_SAMPLES_STEREO; s += 4) { + if (!bufferToAdd->isStereo()) { + // this is a mono buffer, which means it gets full attenuation and spatialization - // setup the int16_t variables for the two sample sets - correctBufferSample[0] = nextOutputStart[s / 2] * attenuationCoefficient; - correctBufferSample[1] = nextOutputStart[(s / 2) + 1] * attenuationCoefficient; + // if the bearing relative angle to source is > 0 then the delayed channel is the right one + int delayedChannelOffset = (bearingRelativeAngleToSource > 0.0f) ? 1 : 0; + int goodChannelOffset = delayedChannelOffset == 0 ? 1 : 0; - delayedChannelIndex = s + (numSamplesDelay * 2) + delayedChannelOffset; + const int16_t* bufferStart = bufferToAdd->getBuffer(); + int ringBufferSampleCapacity = bufferToAdd->getSampleCapacity(); - delayBufferSample[0] = correctBufferSample[0] * weakChannelAmplitudeRatio; - delayBufferSample[1] = correctBufferSample[1] * weakChannelAmplitudeRatio; + int16_t correctBufferSample[2], delayBufferSample[2]; + int delayedChannelIndex = 0; - __m64 bufferSamples = _mm_set_pi16(_clientSamples[s + goodChannelOffset], - _clientSamples[s + goodChannelOffset + SINGLE_STEREO_OFFSET], - _clientSamples[delayedChannelIndex], - _clientSamples[delayedChannelIndex + SINGLE_STEREO_OFFSET]); - __m64 addedSamples = _mm_set_pi16(correctBufferSample[0], correctBufferSample[1], - delayBufferSample[0], delayBufferSample[1]); + const int SINGLE_STEREO_OFFSET = 2; - // perform the MMX add (with saturation) of two correct and delayed samples - __m64 mmxResult = _mm_adds_pi16(bufferSamples, addedSamples); - int16_t* shortResults = reinterpret_cast(&mmxResult); - - // assign the results from the result of the mmx arithmetic - _clientSamples[s + goodChannelOffset] = shortResults[3]; - _clientSamples[s + goodChannelOffset + SINGLE_STEREO_OFFSET] = shortResults[2]; - _clientSamples[delayedChannelIndex] = shortResults[1]; - _clientSamples[delayedChannelIndex + SINGLE_STEREO_OFFSET] = shortResults[0]; - } - - // The following code is pretty gross and redundant, but AFAIK it's the best way to avoid - // too many conditionals in handling the delay samples at the beginning of _clientSamples. - // Basically we try to take the samples in batches of four, and then handle the remainder - // conditionally to get rid of the rest. - - const int DOUBLE_STEREO_OFFSET = 4; - const int TRIPLE_STEREO_OFFSET = 6; - - if (numSamplesDelay > 0) { - // if there was a sample delay for this buffer, we need to pull samples prior to the nextOutput - // to stick at the beginning - float attenuationAndWeakChannelRatio = attenuationCoefficient * weakChannelAmplitudeRatio; - const int16_t* delayNextOutputStart = nextOutputStart - numSamplesDelay; - if (delayNextOutputStart < bufferStart) { - delayNextOutputStart = bufferStart + ringBufferSampleCapacity - numSamplesDelay; + for (int s = 0; s < NETWORK_BUFFER_LENGTH_SAMPLES_STEREO; s += 4) { + + // setup the int16_t variables for the two sample sets + correctBufferSample[0] = nextOutputStart[s / 2] * attenuationCoefficient; + correctBufferSample[1] = nextOutputStart[(s / 2) + 1] * attenuationCoefficient; + + delayedChannelIndex = s + (numSamplesDelay * 2) + delayedChannelOffset; + + delayBufferSample[0] = correctBufferSample[0] * weakChannelAmplitudeRatio; + delayBufferSample[1] = correctBufferSample[1] * weakChannelAmplitudeRatio; + + __m64 bufferSamples = _mm_set_pi16(_clientSamples[s + goodChannelOffset], + _clientSamples[s + goodChannelOffset + SINGLE_STEREO_OFFSET], + _clientSamples[delayedChannelIndex], + _clientSamples[delayedChannelIndex + SINGLE_STEREO_OFFSET]); + __m64 addedSamples = _mm_set_pi16(correctBufferSample[0], correctBufferSample[1], + delayBufferSample[0], delayBufferSample[1]); + + // perform the MMX add (with saturation) of two correct and delayed samples + __m64 mmxResult = _mm_adds_pi16(bufferSamples, addedSamples); + int16_t* shortResults = reinterpret_cast(&mmxResult); + + // assign the results from the result of the mmx arithmetic + _clientSamples[s + goodChannelOffset] = shortResults[3]; + _clientSamples[s + goodChannelOffset + SINGLE_STEREO_OFFSET] = shortResults[2]; + _clientSamples[delayedChannelIndex] = shortResults[1]; + _clientSamples[delayedChannelIndex + SINGLE_STEREO_OFFSET] = shortResults[0]; } - int i = 0; + // The following code is pretty gross and redundant, but AFAIK it's the best way to avoid + // too many conditionals in handling the delay samples at the beginning of _clientSamples. + // Basically we try to take the samples in batches of four, and then handle the remainder + // conditionally to get rid of the rest. - while (i + 3 < numSamplesDelay) { - // handle the first cases where we can MMX add four samples at once + const int DOUBLE_STEREO_OFFSET = 4; + const int TRIPLE_STEREO_OFFSET = 6; + + if (numSamplesDelay > 0) { + // if there was a sample delay for this buffer, we need to pull samples prior to the nextOutput + // to stick at the beginning + float attenuationAndWeakChannelRatio = attenuationCoefficient * weakChannelAmplitudeRatio; + const int16_t* delayNextOutputStart = nextOutputStart - numSamplesDelay; + if (delayNextOutputStart < bufferStart) { + delayNextOutputStart = bufferStart + ringBufferSampleCapacity - numSamplesDelay; + } + + int i = 0; + + while (i + 3 < numSamplesDelay) { + // handle the first cases where we can MMX add four samples at once + int parentIndex = i * 2; + __m64 bufferSamples = _mm_set_pi16(_clientSamples[parentIndex + delayedChannelOffset], + _clientSamples[parentIndex + SINGLE_STEREO_OFFSET + delayedChannelOffset], + _clientSamples[parentIndex + DOUBLE_STEREO_OFFSET + delayedChannelOffset], + _clientSamples[parentIndex + TRIPLE_STEREO_OFFSET + delayedChannelOffset]); + __m64 addSamples = _mm_set_pi16(delayNextOutputStart[i] * attenuationAndWeakChannelRatio, + delayNextOutputStart[i + 1] * attenuationAndWeakChannelRatio, + delayNextOutputStart[i + 2] * attenuationAndWeakChannelRatio, + delayNextOutputStart[i + 3] * attenuationAndWeakChannelRatio); + __m64 mmxResult = _mm_adds_pi16(bufferSamples, addSamples); + int16_t* shortResults = reinterpret_cast(&mmxResult); + + _clientSamples[parentIndex + delayedChannelOffset] = shortResults[3]; + _clientSamples[parentIndex + SINGLE_STEREO_OFFSET + delayedChannelOffset] = shortResults[2]; + _clientSamples[parentIndex + DOUBLE_STEREO_OFFSET + delayedChannelOffset] = shortResults[1]; + _clientSamples[parentIndex + TRIPLE_STEREO_OFFSET + delayedChannelOffset] = shortResults[0]; + + // push the index + i += 4; + } + int parentIndex = i * 2; - __m64 bufferSamples = _mm_set_pi16(_clientSamples[parentIndex + delayedChannelOffset], - _clientSamples[parentIndex + SINGLE_STEREO_OFFSET + delayedChannelOffset], - _clientSamples[parentIndex + DOUBLE_STEREO_OFFSET + delayedChannelOffset], - _clientSamples[parentIndex + TRIPLE_STEREO_OFFSET + delayedChannelOffset]); - __m64 addSamples = _mm_set_pi16(delayNextOutputStart[i] * attenuationAndWeakChannelRatio, - delayNextOutputStart[i + 1] * attenuationAndWeakChannelRatio, - delayNextOutputStart[i + 2] * attenuationAndWeakChannelRatio, - delayNextOutputStart[i + 3] * attenuationAndWeakChannelRatio); - __m64 mmxResult = _mm_adds_pi16(bufferSamples, addSamples); - int16_t* shortResults = reinterpret_cast(&mmxResult); - _clientSamples[parentIndex + delayedChannelOffset] = shortResults[3]; - _clientSamples[parentIndex + SINGLE_STEREO_OFFSET + delayedChannelOffset] = shortResults[2]; - _clientSamples[parentIndex + DOUBLE_STEREO_OFFSET + delayedChannelOffset] = shortResults[1]; - _clientSamples[parentIndex + TRIPLE_STEREO_OFFSET + delayedChannelOffset] = shortResults[0]; - - // push the index - i += 4; + if (i + 2 < numSamplesDelay) { + // MMX add only three delayed samples + + __m64 bufferSamples = _mm_set_pi16(_clientSamples[parentIndex + delayedChannelOffset], + _clientSamples[parentIndex + SINGLE_STEREO_OFFSET + delayedChannelOffset], + _clientSamples[parentIndex + DOUBLE_STEREO_OFFSET + delayedChannelOffset], + 0); + __m64 addSamples = _mm_set_pi16(delayNextOutputStart[i] * attenuationAndWeakChannelRatio, + delayNextOutputStart[i + 1] * attenuationAndWeakChannelRatio, + delayNextOutputStart[i + 2] * attenuationAndWeakChannelRatio, + 0); + __m64 mmxResult = _mm_adds_pi16(bufferSamples, addSamples); + int16_t* shortResults = reinterpret_cast(&mmxResult); + + _clientSamples[parentIndex + delayedChannelOffset] = shortResults[3]; + _clientSamples[parentIndex + SINGLE_STEREO_OFFSET + delayedChannelOffset] = shortResults[2]; + _clientSamples[parentIndex + DOUBLE_STEREO_OFFSET + delayedChannelOffset] = shortResults[1]; + + } 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); + __m64 addSamples = _mm_set_pi16(delayNextOutputStart[i] * attenuationAndWeakChannelRatio, + delayNextOutputStart[i + 1] * attenuationAndWeakChannelRatio, 0, 0); + + __m64 mmxResult = _mm_adds_pi16(bufferSamples, addSamples); + int16_t* shortResults = reinterpret_cast(&mmxResult); + + _clientSamples[parentIndex + delayedChannelOffset] = shortResults[3]; + _clientSamples[parentIndex + SINGLE_STEREO_OFFSET + delayedChannelOffset] = shortResults[2]; + + } else if (i < numSamplesDelay) { + // MMX add a single delayed sample + __m64 bufferSamples = _mm_set_pi16(_clientSamples[parentIndex + delayedChannelOffset], 0, 0, 0); + __m64 addSamples = _mm_set_pi16(delayNextOutputStart[i] * attenuationAndWeakChannelRatio, 0, 0, 0); + + __m64 mmxResult = _mm_adds_pi16(bufferSamples, addSamples); + int16_t* shortResults = reinterpret_cast(&mmxResult); + + _clientSamples[parentIndex + delayedChannelOffset] = shortResults[3]; + } } + } else { + // stereo buffer - do attenuation but no sample delay for spatialization + qDebug() << "Adding a stereo buffer"; - int parentIndex = i * 2; - - if (i + 2 < numSamplesDelay) { - // MMX add only three delayed samples + for (int s = 0; s < NETWORK_BUFFER_LENGTH_SAMPLES_STEREO; s += 4) { + // use MMX to clamp four additions at a time - __m64 bufferSamples = _mm_set_pi16(_clientSamples[parentIndex + delayedChannelOffset], - _clientSamples[parentIndex + SINGLE_STEREO_OFFSET + delayedChannelOffset], - _clientSamples[parentIndex + DOUBLE_STEREO_OFFSET + delayedChannelOffset], - 0); - __m64 addSamples = _mm_set_pi16(delayNextOutputStart[i] * attenuationAndWeakChannelRatio, - delayNextOutputStart[i + 1] * attenuationAndWeakChannelRatio, - delayNextOutputStart[i + 2] * attenuationAndWeakChannelRatio, - 0); - __m64 mmxResult = _mm_adds_pi16(bufferSamples, addSamples); - int16_t* shortResults = reinterpret_cast(&mmxResult); - - _clientSamples[parentIndex + delayedChannelOffset] = shortResults[3]; - _clientSamples[parentIndex + SINGLE_STEREO_OFFSET + delayedChannelOffset] = shortResults[2]; - _clientSamples[parentIndex + DOUBLE_STEREO_OFFSET + delayedChannelOffset] = shortResults[1]; - - } 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); - __m64 addSamples = _mm_set_pi16(delayNextOutputStart[i] * attenuationAndWeakChannelRatio, - delayNextOutputStart[i + 1] * attenuationAndWeakChannelRatio, 0, 0); + __m64 bufferSamples = _mm_set_pi16(_clientSamples[s], _clientSamples[s + 1], + _clientSamples[s + 2], _clientSamples[s + 3]); + __m64 addSamples = _mm_set_pi16(nextOutputStart[s] * attenuationCoefficient, + nextOutputStart[s + 1] * attenuationCoefficient, + nextOutputStart[s + 2] * attenuationCoefficient, + nextOutputStart[s + 3] * attenuationCoefficient); __m64 mmxResult = _mm_adds_pi16(bufferSamples, addSamples); int16_t* shortResults = reinterpret_cast(&mmxResult); - _clientSamples[parentIndex + delayedChannelOffset] = shortResults[3]; - _clientSamples[parentIndex + SINGLE_STEREO_OFFSET + delayedChannelOffset] = shortResults[2]; - - } else if (i < numSamplesDelay) { - // MMX add a single delayed sample - __m64 bufferSamples = _mm_set_pi16(_clientSamples[parentIndex + delayedChannelOffset], 0, 0, 0); - __m64 addSamples = _mm_set_pi16(delayNextOutputStart[i] * attenuationAndWeakChannelRatio, 0, 0, 0); - - __m64 mmxResult = _mm_adds_pi16(bufferSamples, addSamples); - int16_t* shortResults = reinterpret_cast(&mmxResult); - - _clientSamples[parentIndex + delayedChannelOffset] = shortResults[3]; + _clientSamples[s] = shortResults[3]; + _clientSamples[s + 1] = shortResults[2]; + _clientSamples[s + 2] = shortResults[1]; + _clientSamples[s + 3] = shortResults[0]; } } } diff --git a/assignment-client/src/audio/AudioMixerClientData.cpp b/assignment-client/src/audio/AudioMixerClientData.cpp index 85b8dde690..e21fadbd16 100644 --- a/assignment-client/src/audio/AudioMixerClientData.cpp +++ b/assignment-client/src/audio/AudioMixerClientData.cpp @@ -50,10 +50,22 @@ int AudioMixerClientData::parseData(const QByteArray& packet) { // grab the AvatarAudioRingBuffer from the vector (or create it if it doesn't exist) AvatarAudioRingBuffer* avatarRingBuffer = getAvatarAudioRingBuffer(); + + // read the first byte after the header to see if this is a stereo or mono buffer + quint8 channelFlag = packet.at(numBytesForPacketHeader(packet)); + bool isStereo = channelFlag == 1; + + if (avatarRingBuffer && avatarRingBuffer->isStereo() != isStereo) { + // there's a mismatch in the buffer channels for the incoming and current buffer + // so delete our current buffer and create a new one + _ringBuffers.removeOne(avatarRingBuffer); + avatarRingBuffer->deleteLater(); + avatarRingBuffer = NULL; + } if (!avatarRingBuffer) { // we don't have an AvatarAudioRingBuffer yet, so add it - avatarRingBuffer = new AvatarAudioRingBuffer(); + avatarRingBuffer = new AvatarAudioRingBuffer(isStereo); _ringBuffers.push_back(avatarRingBuffer); } diff --git a/assignment-client/src/audio/AudioMixerClientData.h b/assignment-client/src/audio/AudioMixerClientData.h index a5f03ebd15..70b653301b 100644 --- a/assignment-client/src/audio/AudioMixerClientData.h +++ b/assignment-client/src/audio/AudioMixerClientData.h @@ -24,14 +24,14 @@ public: AudioMixerClientData(); ~AudioMixerClientData(); - const std::vector getRingBuffers() const { return _ringBuffers; } + const QList getRingBuffers() const { return _ringBuffers; } AvatarAudioRingBuffer* getAvatarAudioRingBuffer() const; int parseData(const QByteArray& packet); void checkBuffersBeforeFrameSend(int jitterBufferLengthSamples); void pushBuffersAfterFrameSend(); private: - std::vector _ringBuffers; + QList _ringBuffers; }; #endif // hifi_AudioMixerClientData_h diff --git a/assignment-client/src/audio/AvatarAudioRingBuffer.cpp b/assignment-client/src/audio/AvatarAudioRingBuffer.cpp index 9a7c2839d8..5613a64cc4 100644 --- a/assignment-client/src/audio/AvatarAudioRingBuffer.cpp +++ b/assignment-client/src/audio/AvatarAudioRingBuffer.cpp @@ -13,8 +13,8 @@ #include "AvatarAudioRingBuffer.h" -AvatarAudioRingBuffer::AvatarAudioRingBuffer() : - PositionalAudioRingBuffer(PositionalAudioRingBuffer::Microphone) { +AvatarAudioRingBuffer::AvatarAudioRingBuffer(bool isStereo) : + PositionalAudioRingBuffer(PositionalAudioRingBuffer::Microphone, isStereo) { } diff --git a/assignment-client/src/audio/AvatarAudioRingBuffer.h b/assignment-client/src/audio/AvatarAudioRingBuffer.h index 1e61a82f68..f842c2aa33 100644 --- a/assignment-client/src/audio/AvatarAudioRingBuffer.h +++ b/assignment-client/src/audio/AvatarAudioRingBuffer.h @@ -18,7 +18,7 @@ class AvatarAudioRingBuffer : public PositionalAudioRingBuffer { public: - AvatarAudioRingBuffer(); + AvatarAudioRingBuffer(bool isStereo = false); int parseData(const QByteArray& packet); private: diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 1575aa524f..39392a5361 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -640,6 +640,9 @@ void Audio::handleAudioInput() { } char* currentPacketPtr = audioDataPacket + populatePacketHeader(audioDataPacket, packetType); + + // set the mono/stereo byte + *currentPacketPtr++ = isStereo; // memcpy the three float positions memcpy(currentPacketPtr, &headPosition, sizeof(headPosition)); @@ -649,9 +652,6 @@ void Audio::handleAudioInput() { memcpy(currentPacketPtr, &headOrientation, sizeof(headOrientation)); currentPacketPtr += sizeof(headOrientation); - // set the mono/stereo byte - *currentPacketPtr++ = isStereo; - nodeList->writeDatagram(audioDataPacket, numAudioBytes + leadingBytes, audioMixer); Application::getInstance()->getBandwidthMeter()->outputStream(BandwidthMeter::AUDIO) diff --git a/libraries/audio/src/PositionalAudioRingBuffer.cpp b/libraries/audio/src/PositionalAudioRingBuffer.cpp index 0a3d2d0c16..94a88897e3 100644 --- a/libraries/audio/src/PositionalAudioRingBuffer.cpp +++ b/libraries/audio/src/PositionalAudioRingBuffer.cpp @@ -41,6 +41,9 @@ int PositionalAudioRingBuffer::parseData(const QByteArray& packet) { // skip the packet header (includes the source UUID) int readBytes = numBytesForPacketHeader(packet); + // hop over the channel flag that has already been read in AudioMixerClientData + readBytes += sizeof(quint8); + // read the positional data readBytes += parsePositionalData(packet.mid(readBytes)); if (packetTypeForPacket(packet) == PacketTypeSilentAudioFrame) { diff --git a/libraries/audio/src/PositionalAudioRingBuffer.h b/libraries/audio/src/PositionalAudioRingBuffer.h index 1864271d5f..17a663d5f6 100644 --- a/libraries/audio/src/PositionalAudioRingBuffer.h +++ b/libraries/audio/src/PositionalAudioRingBuffer.h @@ -41,6 +41,8 @@ public: bool shouldLoopbackForNode() const { return _shouldLoopbackForNode; } + bool isStereo() const { return _isStereo; } + PositionalAudioRingBuffer::Type getType() const { return _type; } const glm::vec3& getPosition() const { return _position; } const glm::quat& getOrientation() const { return _orientation; } From 0fc6354b6cb14b5391761252183a167fb9999b32 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 6 Jun 2014 11:18:55 -0700 Subject: [PATCH 19/52] Fix for streaming the same object. --- libraries/metavoxels/src/Bitstream.cpp | 6 ++++-- tests/metavoxels/src/MetavoxelTests.cpp | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/libraries/metavoxels/src/Bitstream.cpp b/libraries/metavoxels/src/Bitstream.cpp index 30d34580d7..bc187d9f3d 100644 --- a/libraries/metavoxels/src/Bitstream.cpp +++ b/libraries/metavoxels/src/Bitstream.cpp @@ -224,7 +224,8 @@ void Bitstream::persistWriteMappings(const WriteMappings& mappings) { } connect(it.key().data(), SIGNAL(destroyed(QObject*)), SLOT(clearSharedObject(QObject*))); QPointer& reference = _sharedObjectReferences[it.key()->getOriginID()]; - if (reference) { + if (reference && reference != it.key()) { + // the object has been replaced by a successor, so we can forget about the original _sharedObjectStreamer.removePersistentID(reference); reference->disconnect(this); } @@ -258,7 +259,8 @@ void Bitstream::persistReadMappings(const ReadMappings& mappings) { continue; } QPointer& reference = _sharedObjectReferences[it.value()->getRemoteOriginID()]; - if (reference) { + if (reference && reference != it.value()) { + // the object has been replaced by a successor, so we can forget about the original _sharedObjectStreamer.removePersistentValue(reference.data()); } reference = it.value(); diff --git a/tests/metavoxels/src/MetavoxelTests.cpp b/tests/metavoxels/src/MetavoxelTests.cpp index c4d973ad05..eec26ae411 100644 --- a/tests/metavoxels/src/MetavoxelTests.cpp +++ b/tests/metavoxels/src/MetavoxelTests.cpp @@ -183,7 +183,7 @@ bool MetavoxelTests::run() { bob.setOther(&alice); // perform a large number of simulation iterations - const int SIMULATION_ITERATIONS = 100000; + const int SIMULATION_ITERATIONS = 10000; for (int i = 0; i < SIMULATION_ITERATIONS; i++) { if (alice.simulate(i) || bob.simulate(i)) { return true; @@ -241,7 +241,7 @@ Endpoint::Endpoint(const QByteArray& datagramHeader) : _receiveRecords.append(receiveRecord); // create the object that represents out delta-encoded state - //_localState = new TestSharedObjectA(); + _localState = new TestSharedObjectA(); connect(_sequencer->getReliableInputChannel(), SIGNAL(receivedMessage(const QVariant&)), SLOT(handleReliableMessage(const QVariant&))); From 69adf8d0dd8edcb3314016ce8076d9b4c26e429a Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 6 Jun 2014 11:19:43 -0700 Subject: [PATCH 20/52] Removed extra debug, fix model jumping when releasing one of the two triggers. --- examples/editModels.js | 50 ++++++++++-------------------------------- 1 file changed, 11 insertions(+), 39 deletions(-) diff --git a/examples/editModels.js b/examples/editModels.js index 67e2bdb198..93a34b9a3a 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -356,7 +356,6 @@ function controller(wichSide) { var factor2 = Vec3.dot(forward, this.modelPositionAtGrab) - d; var vector = Vec3.subtract(this.palmPosition, this.positionAtGrab); - print("factor1: " + factor1 + ", factor2: " + factor2); if (factor2 < 0) { factor2 = 0; } @@ -395,46 +394,8 @@ function controller(wichSide) { for (var i = 0; i < indicesToRemove.length; ++i) { this.jointsIntersectingFromStart.splice(this.jointsIntersectingFromStart.indexOf(indicesToRemove[i], 1)); } - - - jointList = MyAvatar.getJointNames(); - - var closestJointIndex = -1; - var closestJointDistance = 999999; - for (var i = 0; i < jointList.length; i++) { - var distance = Vec3.distance(MyAvatar.getJointPosition(jointList[i]), this.oldModelPosition); - if (distance < closestJointDistance) { - closestJointDistance = distance; - closestJointIndex = i; - } - } - - if (closestJointDistance < this.oldModelRadius) { - if (this.jointsIntersectingFromStart.indexOf(closestJointIndex) != -1 || - (leftController.grabbing && rightController.grabbing && - leftController.modelID.id == rightController.modelID.id)) { - // Do nothing - } else { - Vec3.print("Ball at: ", MyAvatar.getJointPosition(closestJointIndex)); - Overlays.editOverlay(this.ballGlowingJoint, { - position: MyAvatar.getJointPosition(closestJointIndex), - glowLevel: 0.25, - visible: true - }); - } - } else { - Overlays.editOverlay(this.ballGlowingJoint, { glowLevel: 0.0, visible: false }); - } } } - this.ballGlowingJoint = Overlays.addOverlay("sphere", { - position: { x: 0, y: 0, z: 0 }, - size: 1, - solid: true, - color: { red: 0, green: 255, blue: 0 }, - alpha: 1, - visible: false, - anchor: "MyAvatar"}); this.update = function () { this.oldPalmPosition = this.palmPosition; @@ -617,6 +578,17 @@ function moveModels() { var w = Vec3.normalize(Vec3.cross(u, v)); rotation = Quat.multiply(Quat.angleAxis(angle, w), leftController.oldModelRotation); + + + leftController.positionAtGrab = leftController.palmPosition; + leftController.rotationAtGrab = leftController.rotation; + leftController.modelPositionAtGrab = leftController.oldModelPosition; + leftController.modelRotationAtGrab = rotation; + + rightController.positionAtGrab = rightController.palmPosition; + rightController.rotationAtGrab = rightController.rotation; + rightController.modelPositionAtGrab = rightController.oldModelPosition; + rightController.modelRotationAtGrab = rotation; break; } From f6011b65d7604ef303ee94f4ba2884e4c9ebfb54 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 6 Jun 2014 11:26:04 -0700 Subject: [PATCH 21/52] fix input loudness for a stereo source --- assignment-client/src/audio/AudioMixer.cpp | 4 +--- .../src/audio/AudioMixerClientData.cpp | 3 ++- interface/src/Audio.cpp | 17 +++++++++++++---- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index f8cfb3140c..61dee6c82b 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -307,9 +307,7 @@ void AudioMixer::addBufferToMixForListeningNodeWithBuffer(PositionalAudioRingBuf } } } else { - // stereo buffer - do attenuation but no sample delay for spatialization - qDebug() << "Adding a stereo buffer"; - + // stereo buffer - do attenuation but no sample delay for spatialization for (int s = 0; s < NETWORK_BUFFER_LENGTH_SAMPLES_STEREO; s += 4) { // use MMX to clamp four additions at a time diff --git a/assignment-client/src/audio/AudioMixerClientData.cpp b/assignment-client/src/audio/AudioMixerClientData.cpp index e21fadbd16..7fb2a7dcab 100644 --- a/assignment-client/src/audio/AudioMixerClientData.cpp +++ b/assignment-client/src/audio/AudioMixerClientData.cpp @@ -118,7 +118,8 @@ void AudioMixerClientData::pushBuffersAfterFrameSend() { PositionalAudioRingBuffer* audioBuffer = _ringBuffers[i]; if (audioBuffer->willBeAddedToMix()) { - audioBuffer->shiftReadPosition(NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL); + audioBuffer->shiftReadPosition(audioBuffer->isStereo() + ? NETWORK_BUFFER_LENGTH_SAMPLES_STEREO : NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL); audioBuffer->setWillBeAddedToMix(false); } else if (audioBuffer->getType() == PositionalAudioRingBuffer::Injector diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 39392a5361..b012daa017 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -306,7 +306,7 @@ void linearResampling(int16_t* sourceSamples, int16_t* destinationSamples, } else { // this is a 48 to 24 resampling but both source and destination are two channels // squish two samples into one in each channel - for (int i = 0; i < numSourceSamples; i += 2) { + for (int i = 0; i < numSourceSamples; i += 4) { destinationSamples[i / 2] = (sourceSamples[i] / 2) + (sourceSamples[i + 2] / 2); destinationSamples[(i / 2) + 1] = (sourceSamples[i + 1] / 2) + (sourceSamples[i + 3] / 2); } @@ -585,6 +585,14 @@ void Audio::handleAudioInput() { _lastInputLoudness = 0; } } + } else { + float loudness = 0.0f; + + for (int i = 0; i < NETWORK_BUFFER_LENGTH_SAMPLES_STEREO; i++) { + loudness += fabsf(networkAudioSamples[i]); + } + + _lastInputLoudness = fabs(loudness / NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL); } } else { // our input loudness is 0, since we're muted @@ -626,11 +634,12 @@ void Audio::handleAudioInput() { packetType = PacketTypeSilentAudioFrame; // we need to indicate how many silent samples this is to the audio mixer - audioDataPacket[0] = NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL; + audioDataPacket[0] = _isStereoInput + ? NETWORK_BUFFER_LENGTH_SAMPLES_STEREO + : NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL; numAudioBytes = sizeof(int16_t); - } else { - numAudioBytes = NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL; + numAudioBytes = _isStereoInput ? NETWORK_BUFFER_LENGTH_BYTES_STEREO : NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL; if (Menu::getInstance()->isOptionChecked(MenuOption::EchoServerAudio)) { packetType = PacketTypeMicrophoneAudioWithEcho; From 56d9bc5215a60b72cc6696e9d21eb14f4caf312d Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 6 Jun 2014 11:37:45 -0700 Subject: [PATCH 22/52] Working on delta-streaming tests. --- tests/metavoxels/src/MetavoxelTests.cpp | 33 ++++++++++++++++++++++++- tests/metavoxels/src/MetavoxelTests.h | 1 + 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/tests/metavoxels/src/MetavoxelTests.cpp b/tests/metavoxels/src/MetavoxelTests.cpp index eec26ae411..b2dcc1dd45 100644 --- a/tests/metavoxels/src/MetavoxelTests.cpp +++ b/tests/metavoxels/src/MetavoxelTests.cpp @@ -38,6 +38,7 @@ static int streamedBytesSent = 0; static int streamedBytesReceived = 0; static int sharedObjectsCreated = 0; static int sharedObjectsDestroyed = 0; +static int objectMutationsPerformed = 0; static QByteArray createRandomBytes(int minimumSize, int maximumSize) { QByteArray bytes(randIntInRange(minimumSize, maximumSize), 0); @@ -196,6 +197,7 @@ bool MetavoxelTests::run() { qDebug() << "Sent" << streamedBytesSent << "streamed bytes, received" << streamedBytesReceived; qDebug() << "Sent" << datagramsSent << "datagrams, received" << datagramsReceived; qDebug() << "Created" << sharedObjectsCreated << "shared objects, destroyed" << sharedObjectsDestroyed; + qDebug() << "Performed" << objectMutationsPerformed << "object mutations"; qDebug(); qDebug() << "Running serialization tests..."; @@ -272,13 +274,37 @@ static QVariant createRandomMessage() { TestMessageB message = { createRandomBytes(), createRandomSharedObject(), getRandomTestEnum() }; return QVariant::fromValue(message); } - case 2: default: { return QVariant::fromValue(createRandomMessageC()); } } } +static SharedObjectPointer mutate(const SharedObjectPointer& state) { + switch(randIntInRange(0, 3)) { + case 0: { + SharedObjectPointer newState = state->clone(true); + static_cast(newState.data())->setFoo(randFloat()); + objectMutationsPerformed++; + return newState; + } + case 1: { + SharedObjectPointer newState = state->clone(true); + static_cast(newState.data())->setBaz(getRandomTestEnum()); + objectMutationsPerformed++; + return newState; + } + case 2: { + SharedObjectPointer newState = state->clone(true); + static_cast(newState.data())->setBong(getRandomTestFlags()); + objectMutationsPerformed++; + return newState; + } + default: + return state; + } +} + static bool messagesEqual(const QVariant& firstMessage, const QVariant& secondMessage) { int type = firstMessage.userType(); if (secondMessage.userType() != type) { @@ -337,6 +363,9 @@ bool Endpoint::simulate(int iterationNumber) { _reliableMessagesToSend -= 1.0f; } + // tweak the local state + _localState = mutate(_localState); + // send a packet try { Bitstream& out = _sequencer->startPacket(); @@ -405,6 +434,8 @@ void Endpoint::readMessage(Bitstream& in) { SequencedTestMessage message; in >> message; + _remoteState = message.state; + // record the receipt ReceiveRecord record = { _sequencer->getIncomingPacketNumber(), message.state }; _receiveRecords.append(record); diff --git a/tests/metavoxels/src/MetavoxelTests.h b/tests/metavoxels/src/MetavoxelTests.h index dc294692af..345ea624df 100644 --- a/tests/metavoxels/src/MetavoxelTests.h +++ b/tests/metavoxels/src/MetavoxelTests.h @@ -76,6 +76,7 @@ private: QList _receiveRecords; SharedObjectPointer _localState; + SharedObjectPointer _remoteState; Endpoint* _other; QList > _delayedDatagrams; From a7a9656ac74c1652ed0a3ff98435f4bd067d5eef Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 6 Jun 2014 11:47:34 -0700 Subject: [PATCH 23/52] add a mixer crash guard in addSilentFrame --- libraries/audio/src/PositionalAudioRingBuffer.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libraries/audio/src/PositionalAudioRingBuffer.cpp b/libraries/audio/src/PositionalAudioRingBuffer.cpp index 94a88897e3..555c3d937d 100644 --- a/libraries/audio/src/PositionalAudioRingBuffer.cpp +++ b/libraries/audio/src/PositionalAudioRingBuffer.cpp @@ -55,7 +55,9 @@ int PositionalAudioRingBuffer::parseData(const QByteArray& packet) { readBytes += sizeof(int16_t); - addSilentFrame(numSilentSamples); + if (numSilentSamples > 0) { + addSilentFrame(numSilentSamples); + } } else { // there is audio data to read readBytes += writeData(packet.data() + readBytes, packet.size() - readBytes); From 8cd5ec3b54e4e5b0f1cdebf2bf20833e8ebcac2b Mon Sep 17 00:00:00 2001 From: wangyix Date: Fri, 6 Jun 2014 11:50:34 -0700 Subject: [PATCH 24/52] started work on sending nack packets from client --- .../src/octree/OctreeSendThread.cpp | 4 +- interface/src/Application.cpp | 59 ++++++++++++++++++- interface/src/Application.h | 6 ++ libraries/octree/src/OctreeSceneStats.cpp | 15 +++++ libraries/octree/src/OctreeSceneStats.h | 4 ++ 5 files changed, 85 insertions(+), 3 deletions(-) diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index befea80380..032b45fcdf 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -288,12 +288,12 @@ int OctreeSendThread::handlePacketSend(OctreeQueryNode* nodeData, int& trueBytes int OctreeSendThread::resendNackedPackets(OctreeQueryNode* nodeData) { - const int maxPacketsSent = 10; + const int MAX_PACKETS_RESEND = 10; int packetsSent = 0; const QByteArray* packet; - while (nodeData->hasNextNackedPacket() && packetsSent < maxPacketsSent) { + while (nodeData->hasNextNackedPacket() && packetsSent < MAX_PACKETS_RESEND) { packet = nodeData->getNextNackedPacket(); // packet will be NULL if it's not in nodeData's packet history if (packet) { diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index de3c354b27..358bb1bde3 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -167,7 +167,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : _applicationOverlay(), _runningScriptsWidget(new RunningScriptsWidget(_window)), _runningScriptsWidgetWasVisible(false), - _trayIcon(new QSystemTrayIcon(_window)) + _trayIcon(new QSystemTrayIcon(_window)), + _lastNackTime(usecTimestampNow()) { // read the ApplicationInfo.ini file for Name/Version/Domain information QSettings applicationInfo(Application::resourcesPath() + "info/ApplicationInfo.ini", QSettings::IniFormat); @@ -2091,7 +2092,63 @@ void Application::updateMyAvatar(float deltaTime) { _lastQueriedViewFrustum = _viewFrustum; } } + +// sent a nack packet containing missing sequence numbers of received packets +{ + quint64 now = usecTimestampNow(); + quint64 sinceLastNack = now - _lastNackTime; + const quint64 TOO_LONG_SINCE_LAST_NACK = 100 * MSECS_PER_SECOND; + if (sinceLastNack > TOO_LONG_SINCE_LAST_NACK) { + _lastNackTime = now; + + //_octreeServerSceneStats- + } } +} + + +void Application::sendNack() { + /* + // now that we know the node ID, let's add these stats to the stats for that node... + _octreeSceneStatsLock.lockForWrite(); + if (_octreeServerSceneStats.find(nodeUUID) != _octreeServerSceneStats.end()) { + OctreeSceneStats& stats = _octreeServerSceneStats[nodeUUID]; + stats.trackIncomingOctreePacket(packet, wasStatsPacket, sendingNode->getClockSkewUsec()); + } + _octreeSceneStatsLock.unlock(); + */ + + char packet[MAX_PACKET_SIZE]; + NodeList* nodeList = NodeList::getInstance(); + + // iterates thru all nodes in NodeList + foreach(const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) { + + char* dataAt = packet; + int bytesRemaining = MAX_PACKET_SIZE; + + int numBytesPacketHeader = populatePacketHeader(packet, PacketTypeOctreeDataNack, node->getUUID()); + dataAt += numBytesPacketHeader; + bytesRemaining -= numBytesPacketHeader; + + + + uint16_t numSequenceNumbers; + + + + + OctreeSceneStats& stats = _octreeServerSceneStats[node->getUUID()]; + int numSequenceNumbersAvailable = stats.getNumSequenceNumberToNack(); + + + // make sure we still have an active socket + nodeList->writeUnverifiedDatagram(reinterpret_cast(queryPacket), packetLength, node); + } +} + + + void Application::queryOctree(NodeType_t serverType, PacketType packetType, NodeToJurisdictionMap& jurisdictions) { diff --git a/interface/src/Application.h b/interface/src/Application.h index f3d9c0fd27..670ec35238 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -411,6 +411,10 @@ private: static void attachNewHeadToNode(Node *newNode); static void* networkReceive(void* args); // network receive thread + void sendNack(); + + + MainWindow* _window; GLCanvas* _glWidget; // our GLCanvas has a couple extra features @@ -580,6 +584,8 @@ private: bool _runningScriptsWidgetWasVisible; QSystemTrayIcon* _trayIcon; + +quint64 _lastNackTime; }; #endif // hifi_Application_h diff --git a/libraries/octree/src/OctreeSceneStats.cpp b/libraries/octree/src/OctreeSceneStats.cpp index 9580ae6d13..a25b72bedd 100644 --- a/libraries/octree/src/OctreeSceneStats.cpp +++ b/libraries/octree/src/OctreeSceneStats.cpp @@ -46,6 +46,7 @@ OctreeSceneStats::OctreeSceneStats() : _incomingReallyLate(0), _incomingPossibleDuplicate(0), _missingSequenceNumbers(), +_sequenceNumbersToNack(), _incomingFlightTimeAverage(samples), _jurisdictionRoot(NULL) { @@ -158,6 +159,7 @@ void OctreeSceneStats::copyFromOther(const OctreeSceneStats& other) { _incomingPossibleDuplicate = other._incomingPossibleDuplicate; _missingSequenceNumbers = other._missingSequenceNumbers; +_missingSequenceNumbersToNack = other._missingSequenceNumbersToNack; } @@ -926,6 +928,7 @@ void OctreeSceneStats::trackIncomingOctreePacket(const QByteArray& packet, qDebug() << "found it in _missingSequenceNumbers"; } _missingSequenceNumbers.remove(sequence); +_sequenceNumbersToNack.remove(sequence); _incomingLikelyLost--; _incomingRecovered++; } else { @@ -955,6 +958,7 @@ void OctreeSceneStats::trackIncomingOctreePacket(const QByteArray& packet, _incomingLikelyLost += missing; for(unsigned int missingSequence = expected; missingSequence < sequence; missingSequence++) { _missingSequenceNumbers << missingSequence; +_sequenceNumbersToNack << missingSequence; } } } @@ -982,9 +986,20 @@ void OctreeSceneStats::trackIncomingOctreePacket(const QByteArray& packet, qDebug() << "pruning really old missing sequence:" << missingItem; } _missingSequenceNumbers.remove(missingItem); +_sequenceNumbersToNack.remove(missingItem); } } } } +bool OctreeSceneStats::getNumSequenceNumberToNack() const { + return _sequenceNumbersToNack.size(); +} + +uint16_t OctreeSceneStats::getNextSequenceNumberToNack() { + QSet::Iterator it = _sequenceNumbersToNack.begin(); + uint16_t sequenceNumber = *it; + _sequenceNumbersToNack.remove(sequenceNumber); + return sequenceNumber; +} \ No newline at end of file diff --git a/libraries/octree/src/OctreeSceneStats.h b/libraries/octree/src/OctreeSceneStats.h index ef22fd7c1c..e6664083b0 100644 --- a/libraries/octree/src/OctreeSceneStats.h +++ b/libraries/octree/src/OctreeSceneStats.h @@ -172,6 +172,9 @@ public: quint32 getIncomingPossibleDuplicate() const { return _incomingPossibleDuplicate; } float getIncomingFlightTimeAverage() { return _incomingFlightTimeAverage.getAverage(); } +bool getNumSequenceNumberToNack() const; +uint16_t getNextSequenceNumberToNack(); + private: void copyFromOther(const OctreeSceneStats& other); @@ -273,6 +276,7 @@ private: quint32 _incomingReallyLate; /// out of order and later than MAX_MISSING_SEQUENCE_OLD_AGE late quint32 _incomingPossibleDuplicate; /// out of order possibly a duplicate QSet _missingSequenceNumbers; +QSet _sequenceNumbersToNack; SimpleMovingAverage _incomingFlightTimeAverage; // features related items From 6fdc5df47b729743f8ee14048f27ab914cd0a484 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 6 Jun 2014 11:50:36 -0700 Subject: [PATCH 25/52] bump silent audio frame version --- libraries/audio/src/PositionalAudioRingBuffer.cpp | 4 +--- libraries/networking/src/PacketHeaders.cpp | 1 + 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/libraries/audio/src/PositionalAudioRingBuffer.cpp b/libraries/audio/src/PositionalAudioRingBuffer.cpp index 555c3d937d..94a88897e3 100644 --- a/libraries/audio/src/PositionalAudioRingBuffer.cpp +++ b/libraries/audio/src/PositionalAudioRingBuffer.cpp @@ -55,9 +55,7 @@ int PositionalAudioRingBuffer::parseData(const QByteArray& packet) { readBytes += sizeof(int16_t); - if (numSilentSamples > 0) { - addSilentFrame(numSilentSamples); - } + addSilentFrame(numSilentSamples); } else { // there is audio data to read readBytes += writeData(packet.data() + readBytes, packet.size() - readBytes); diff --git a/libraries/networking/src/PacketHeaders.cpp b/libraries/networking/src/PacketHeaders.cpp index 751c6f45b2..7278f1fbcb 100644 --- a/libraries/networking/src/PacketHeaders.cpp +++ b/libraries/networking/src/PacketHeaders.cpp @@ -49,6 +49,7 @@ PacketVersion versionForPacketType(PacketType type) { switch (type) { case PacketTypeMicrophoneAudioNoEcho: case PacketTypeMicrophoneAudioWithEcho: + case PacketTypeSilentAudioFrame: return 1; case PacketTypeAvatarData: return 3; From 194493ab9b9f1b13843b1f3dc29c047932e92212 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 6 Jun 2014 12:00:47 -0700 Subject: [PATCH 26/52] remove MMX math to fix stereo discrepancies --- assignment-client/src/audio/AudioMixer.cpp | 23 ++++++++-------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 61dee6c82b..b3909660e2 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -310,21 +310,14 @@ void AudioMixer::addBufferToMixForListeningNodeWithBuffer(PositionalAudioRingBuf // stereo buffer - do attenuation but no sample delay for spatialization for (int s = 0; s < NETWORK_BUFFER_LENGTH_SAMPLES_STEREO; s += 4) { // use MMX to clamp four additions at a time - - __m64 bufferSamples = _mm_set_pi16(_clientSamples[s], _clientSamples[s + 1], - _clientSamples[s + 2], _clientSamples[s + 3]); - __m64 addSamples = _mm_set_pi16(nextOutputStart[s] * attenuationCoefficient, - nextOutputStart[s + 1] * attenuationCoefficient, - nextOutputStart[s + 2] * attenuationCoefficient, - nextOutputStart[s + 3] * attenuationCoefficient); - - __m64 mmxResult = _mm_adds_pi16(bufferSamples, addSamples); - int16_t* shortResults = reinterpret_cast(&mmxResult); - - _clientSamples[s] = shortResults[3]; - _clientSamples[s + 1] = shortResults[2]; - _clientSamples[s + 2] = shortResults[1]; - _clientSamples[s + 3] = shortResults[0]; + _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), + MIN_SAMPLE_VALUE, MAX_SAMPLE_VALUE); + _clientSamples[s + 2] = glm::clamp(_clientSamples[s + 2] + (int) (nextOutputStart[s + 2] * attenuationCoefficient), + MIN_SAMPLE_VALUE, MAX_SAMPLE_VALUE); + _clientSamples[s + 3] = glm::clamp(_clientSamples[s + 3] + (int) (nextOutputStart[s + 3] * attenuationCoefficient), + MIN_SAMPLE_VALUE, MAX_SAMPLE_VALUE); } } } From 361461516c8675897adb331edab325db298ebf1a Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 6 Jun 2014 14:26:20 -0700 Subject: [PATCH 27/52] Check the delta-encoded objects, report bytes sent/received. --- tests/metavoxels/src/MetavoxelTests.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/tests/metavoxels/src/MetavoxelTests.cpp b/tests/metavoxels/src/MetavoxelTests.cpp index b2dcc1dd45..81f1840342 100644 --- a/tests/metavoxels/src/MetavoxelTests.cpp +++ b/tests/metavoxels/src/MetavoxelTests.cpp @@ -28,6 +28,8 @@ MetavoxelTests::MetavoxelTests(int& argc, char** argv) : static int datagramsSent = 0; static int datagramsReceived = 0; +static int bytesSent = 0; +static int bytesReceived = 0; static int highPriorityMessagesSent = 0; static int highPriorityMessagesReceived = 0; static int unreliableMessagesSent = 0; @@ -195,7 +197,8 @@ bool MetavoxelTests::run() { qDebug() << "Sent" << unreliableMessagesSent << "unreliable messages, received" << unreliableMessagesReceived; qDebug() << "Sent" << reliableMessagesSent << "reliable messages, received" << reliableMessagesReceived; qDebug() << "Sent" << streamedBytesSent << "streamed bytes, received" << streamedBytesReceived; - qDebug() << "Sent" << datagramsSent << "datagrams, received" << datagramsReceived; + qDebug() << "Sent" << datagramsSent << "datagrams with" << bytesSent << "bytes, received" << + datagramsReceived << "with" << bytesReceived << "bytes"; qDebug() << "Created" << sharedObjectsCreated << "shared objects, destroyed" << sharedObjectsDestroyed; qDebug() << "Performed" << objectMutationsPerformed << "object mutations"; qDebug(); @@ -389,6 +392,7 @@ bool Endpoint::simulate(int iterationNumber) { void Endpoint::sendDatagram(const QByteArray& datagram) { datagramsSent++; + bytesSent += datagram.size(); // some datagrams are dropped const float DROP_PROBABILITY = 0.1f; @@ -414,6 +418,7 @@ void Endpoint::sendDatagram(const QByteArray& datagram) { _other->_sequencer->receivedDatagram(datagram); datagramsReceived++; + bytesReceived += datagram.size(); } void Endpoint::handleHighPriorityMessage(const QVariant& message) { @@ -446,6 +451,9 @@ void Endpoint::readMessage(Bitstream& in) { if (!messagesEqual(it->submessage, message.submessage)) { throw QString("Sent/received unreliable message mismatch."); } + if (!it->state->equals(message.state)) { + throw QString("Delta-encoded object mismatch."); + } _other->_unreliableMessagesSent.erase(_other->_unreliableMessagesSent.begin(), it + 1); unreliableMessagesReceived++; return; From 5c4748556206e940758b46d41625b25deb962f5c Mon Sep 17 00:00:00 2001 From: wangyix Date: Fri, 6 Jun 2014 14:27:51 -0700 Subject: [PATCH 28/52] client-side nack sending complete; ready to test --- interface/src/Application.cpp | 55 ++++++++++++----------- libraries/octree/src/OctreeSceneStats.cpp | 2 +- libraries/octree/src/OctreeSceneStats.h | 2 +- 3 files changed, 32 insertions(+), 27 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 358bb1bde3..7333960689 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2100,23 +2100,13 @@ void Application::updateMyAvatar(float deltaTime) { const quint64 TOO_LONG_SINCE_LAST_NACK = 100 * MSECS_PER_SECOND; if (sinceLastNack > TOO_LONG_SINCE_LAST_NACK) { _lastNackTime = now; - - //_octreeServerSceneStats- + sendNack(); } } } void Application::sendNack() { - /* - // now that we know the node ID, let's add these stats to the stats for that node... - _octreeSceneStatsLock.lockForWrite(); - if (_octreeServerSceneStats.find(nodeUUID) != _octreeServerSceneStats.end()) { - OctreeSceneStats& stats = _octreeServerSceneStats[nodeUUID]; - stats.trackIncomingOctreePacket(packet, wasStatsPacket, sendingNode->getClockSkewUsec()); - } - _octreeSceneStatsLock.unlock(); - */ char packet[MAX_PACKET_SIZE]; NodeList* nodeList = NodeList::getInstance(); @@ -2124,26 +2114,41 @@ void Application::sendNack() { // iterates thru all nodes in NodeList foreach(const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) { - char* dataAt = packet; - int bytesRemaining = MAX_PACKET_SIZE; + if (node->getActiveSocket() && + ( node->getType() == NodeType::VoxelServer + || node->getType() == NodeType::ParticleServer + || node->getType() == NodeType::ModelServer) + ) { - int numBytesPacketHeader = populatePacketHeader(packet, PacketTypeOctreeDataNack, node->getUUID()); - dataAt += numBytesPacketHeader; - bytesRemaining -= numBytesPacketHeader; - - + OctreeSceneStats& stats = _octreeServerSceneStats[node->getUUID()]; - uint16_t numSequenceNumbers; + char* dataAt = packet; + int bytesRemaining = MAX_PACKET_SIZE; + + // pack header + int numBytesPacketHeader = populatePacketHeader(packet, PacketTypeOctreeDataNack, node->getUUID()); + dataAt += numBytesPacketHeader; + bytesRemaining -= numBytesPacketHeader; + + int numPacketsRoomFor = (bytesRemaining - sizeof(uint16_t)) / sizeof(OCTREE_PACKET_SEQUENCE); + // calculate and pack number of sequence numbers + uint16_t numSequenceNumbers = min(stats.getNumSequenceNumbersToNack(), numPacketsRoomFor); + 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); + } - OctreeSceneStats& stats = _octreeServerSceneStats[node->getUUID()]; - int numSequenceNumbersAvailable = stats.getNumSequenceNumberToNack(); - - - // make sure we still have an active socket - nodeList->writeUnverifiedDatagram(reinterpret_cast(queryPacket), packetLength, node); + // make sure we still have an active socket???? + nodeList->writeUnverifiedDatagram(packet, dataAt - packet, node); + } } } diff --git a/libraries/octree/src/OctreeSceneStats.cpp b/libraries/octree/src/OctreeSceneStats.cpp index a25b72bedd..01332fbc46 100644 --- a/libraries/octree/src/OctreeSceneStats.cpp +++ b/libraries/octree/src/OctreeSceneStats.cpp @@ -993,7 +993,7 @@ _sequenceNumbersToNack.remove(missingItem); } -bool OctreeSceneStats::getNumSequenceNumberToNack() const { +int OctreeSceneStats::getNumSequenceNumbersToNack() const { return _sequenceNumbersToNack.size(); } diff --git a/libraries/octree/src/OctreeSceneStats.h b/libraries/octree/src/OctreeSceneStats.h index e6664083b0..ca9bf7c74b 100644 --- a/libraries/octree/src/OctreeSceneStats.h +++ b/libraries/octree/src/OctreeSceneStats.h @@ -172,7 +172,7 @@ public: quint32 getIncomingPossibleDuplicate() const { return _incomingPossibleDuplicate; } float getIncomingFlightTimeAverage() { return _incomingFlightTimeAverage.getAverage(); } -bool getNumSequenceNumberToNack() const; +int getNumSequenceNumbersToNack() const; uint16_t getNextSequenceNumberToNack(); private: From bd2148d4b7eef48d46c6171f801521a4eb1dead8 Mon Sep 17 00:00:00 2001 From: wangyix Date: Fri, 6 Jun 2014 14:33:53 -0700 Subject: [PATCH 29/52] added write lock/unlock ...for _octreeSceneStatsLock --- interface/src/Application.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 7333960689..6d6c7d64ab 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2120,6 +2120,8 @@ void Application::sendNack() { || node->getType() == NodeType::ModelServer) ) { + _octreeSceneStatsLock.lockForWrite(); + OctreeSceneStats& stats = _octreeServerSceneStats[node->getUUID()]; char* dataAt = packet; @@ -2146,6 +2148,8 @@ void Application::sendNack() { dataAt += sizeof(OCTREE_PACKET_SEQUENCE); } + _octreeSceneStatsLock.unlock(); + // make sure we still have an active socket???? nodeList->writeUnverifiedDatagram(packet, dataAt - packet, node); } From 0b1bffa83ca55957d174aa7e7fc0aa3e7916c07d Mon Sep 17 00:00:00 2001 From: wangyix Date: Fri, 6 Jun 2014 15:03:54 -0700 Subject: [PATCH 30/52] added random packet drops; ready to test --- .../src/octree/OctreeSendThread.cpp | 7 +++---- interface/src/Application.cpp | 7 ++++++- libraries/networking/src/LimitedNodeList.cpp | 17 +++++++++++++++++ libraries/networking/src/LimitedNodeList.h | 3 +++ libraries/octree/src/OctreeSceneStats.cpp | 2 +- 5 files changed, 30 insertions(+), 6 deletions(-) diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index 032b45fcdf..e5c47f5d2d 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -181,7 +181,7 @@ int OctreeSendThread::handlePacketSend(OctreeQueryNode* nodeData, int& trueBytes // actually send it OctreeServer::didCallWriteDatagram(this); - NodeList::getInstance()->writeDatagram((char*) statsMessage, statsMessageLength, _node); +NodeList::getInstance()->writeDatagram2(nodeData->getSequenceNumber(), (char*) statsMessage, statsMessageLength, _node); packetSent = true; } else { // not enough room in the packet, send two packets @@ -215,8 +215,7 @@ int OctreeSendThread::handlePacketSend(OctreeQueryNode* nodeData, int& trueBytes packetsSent++; OctreeServer::didCallWriteDatagram(this); - NodeList::getInstance()->writeDatagram((char*) nodeData->getPacket(), nodeData->getPacketLength(), _node); - +NodeList::getInstance()->writeDatagram2(nodeData->getSequenceNumber(), (char*)nodeData->getPacket(), nodeData->getPacketLength(), _node); packetSent = true; thisWastedBytes = MAX_PACKET_SIZE - nodeData->getPacketLength(); @@ -245,7 +244,7 @@ int OctreeSendThread::handlePacketSend(OctreeQueryNode* nodeData, int& trueBytes if (nodeData->isPacketWaiting() && !nodeData->isShuttingDown()) { // just send the voxel packet OctreeServer::didCallWriteDatagram(this); - NodeList::getInstance()->writeDatagram((char*) nodeData->getPacket(), nodeData->getPacketLength(), _node); +NodeList::getInstance()->writeDatagram2(nodeData->getSequenceNumber(), (char*)nodeData->getPacket(), nodeData->getPacketLength(), _node); packetSent = true; int thisWastedBytes = MAX_PACKET_SIZE - nodeData->getPacketLength(); diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 6d6c7d64ab..75980af934 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2097,7 +2097,7 @@ void Application::updateMyAvatar(float deltaTime) { { quint64 now = usecTimestampNow(); quint64 sinceLastNack = now - _lastNackTime; - const quint64 TOO_LONG_SINCE_LAST_NACK = 100 * MSECS_PER_SECOND; + const quint64 TOO_LONG_SINCE_LAST_NACK = 250 * MSECS_PER_SECOND; if (sinceLastNack > TOO_LONG_SINCE_LAST_NACK) { _lastNackTime = now; sendNack(); @@ -2108,6 +2108,8 @@ void Application::updateMyAvatar(float deltaTime) { void Application::sendNack() { +printf("\n\t sendNack()...\n"); + char packet[MAX_PACKET_SIZE]; NodeList* nodeList = NodeList::getInstance(); @@ -2142,11 +2144,14 @@ void Application::sendNack() { dataAt += sizeof(uint16_t); // pack sequence numbers +printf("\t\t packed %d seq #s:", numSequenceNumbers); for (int i = 0; i < numSequenceNumbers; i++) { OCTREE_PACKET_SEQUENCE* sequenceNumberAt = (OCTREE_PACKET_SEQUENCE*)dataAt; *sequenceNumberAt = stats.getNextSequenceNumberToNack(); dataAt += sizeof(OCTREE_PACKET_SEQUENCE); +printf(" %d,", *sequenceNumberAt); } +printf("\n"); _octreeSceneStatsLock.unlock(); diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index c0d7941edf..f9630c9102 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -271,6 +271,23 @@ qint64 LimitedNodeList::writeDatagram(const char* data, qint64 size, const Share return writeDatagram(QByteArray(data, size), destinationNode, overridenSockAddr); } +qint64 LimitedNodeList::writeDatagram2(int seq, const char* data, qint64 size, const SharedNodePointer& destinationNode, + const HifiSockAddr& overridenSockAddr) { + + qint64 ret; + + if (randFloat() < 0.8f) { + ret = writeDatagram(QByteArray(data, size), destinationNode, overridenSockAddr); + } + else { + printf("\t\t\t dropped packet seq = %d!!!\n", seq); + } + + + return ret; +} + + qint64 LimitedNodeList::writeUnverifiedDatagram(const char* data, qint64 size, const SharedNodePointer& destinationNode, const HifiSockAddr& overridenSockAddr) { return writeUnverifiedDatagram(QByteArray(data, size), destinationNode, overridenSockAddr); diff --git a/libraries/networking/src/LimitedNodeList.h b/libraries/networking/src/LimitedNodeList.h index a4bc8022bf..b3481885c8 100644 --- a/libraries/networking/src/LimitedNodeList.h +++ b/libraries/networking/src/LimitedNodeList.h @@ -72,6 +72,9 @@ public: qint64 writeDatagram(const char* data, qint64 size, const SharedNodePointer& destinationNode, const HifiSockAddr& overridenSockAddr = HifiSockAddr()); +qint64 writeDatagram2(int seq, const char* data, qint64 size, const SharedNodePointer& destinationNode, + const HifiSockAddr& overridenSockAddr = HifiSockAddr()); + qint64 writeUnverifiedDatagram(const char* data, qint64 size, const SharedNodePointer& destinationNode, const HifiSockAddr& overridenSockAddr = HifiSockAddr()); diff --git a/libraries/octree/src/OctreeSceneStats.cpp b/libraries/octree/src/OctreeSceneStats.cpp index 01332fbc46..a93b2d0374 100644 --- a/libraries/octree/src/OctreeSceneStats.cpp +++ b/libraries/octree/src/OctreeSceneStats.cpp @@ -159,7 +159,7 @@ void OctreeSceneStats::copyFromOther(const OctreeSceneStats& other) { _incomingPossibleDuplicate = other._incomingPossibleDuplicate; _missingSequenceNumbers = other._missingSequenceNumbers; -_missingSequenceNumbersToNack = other._missingSequenceNumbersToNack; +_sequenceNumbersToNack = other._sequenceNumbersToNack; } From 2fec0a9db603e09e7314a4221e761141a57b127d Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 6 Jun 2014 15:50:28 -0700 Subject: [PATCH 31/52] Fixes for Windows. --- libraries/metavoxels/src/Bitstream.cpp | 87 ++++++++++++++++---------- libraries/metavoxels/src/Bitstream.h | 27 ++++---- 2 files changed, 71 insertions(+), 43 deletions(-) diff --git a/libraries/metavoxels/src/Bitstream.cpp b/libraries/metavoxels/src/Bitstream.cpp index bc187d9f3d..6f4af8ed5f 100644 --- a/libraries/metavoxels/src/Bitstream.cpp +++ b/libraries/metavoxels/src/Bitstream.cpp @@ -79,10 +79,6 @@ IDStreamer& IDStreamer::operator>>(int& value) { return *this; } -static QByteArray getEnumName(const QMetaEnum& metaEnum) { - return QByteArray(metaEnum.scope()) + "::" + metaEnum.name(); -} - int Bitstream::registerMetaObject(const char* className, const QMetaObject* metaObject) { getMetaObjects().insert(className, metaObject); @@ -90,16 +86,6 @@ int Bitstream::registerMetaObject(const char* className, const QMetaObject* meta for (const QMetaObject* superClass = metaObject; superClass; superClass = superClass->superClass()) { getMetaObjectSubClasses().insert(superClass, metaObject); } - - // register the streamers for all enumerators - for (int i = 0; i < metaObject->enumeratorCount(); i++) { - QMetaEnum metaEnum = metaObject->enumerator(i); - const TypeStreamer*& streamer = getEnumStreamers()[QPair(metaEnum.scope(), metaEnum.name())]; - if (!streamer) { - getEnumStreamersByName().insert(getEnumName(metaEnum), streamer = new EnumTypeStreamer(metaEnum)); - } - } - return 0; } @@ -1030,12 +1016,34 @@ QHash& Bitstream::getTypeStreamers() { } QHash, const TypeStreamer*>& Bitstream::getEnumStreamers() { - static QHash, const TypeStreamer*> enumStreamers; + static QHash, const TypeStreamer*> enumStreamers = createEnumStreamers(); + return enumStreamers; +} + +QHash, const TypeStreamer*> Bitstream::createEnumStreamers() { + QHash, const TypeStreamer*> enumStreamers; + foreach (const QMetaObject* metaObject, getMetaObjects()) { + for (int i = 0; i < metaObject->enumeratorCount(); i++) { + QMetaEnum metaEnum = metaObject->enumerator(i); + const TypeStreamer*& streamer = enumStreamers[QPair(metaEnum.scope(), metaEnum.name())]; + if (!streamer) { + streamer = new EnumTypeStreamer(metaEnum); + } + } + } return enumStreamers; } QHash& Bitstream::getEnumStreamersByName() { - static QHash enumStreamersByName; + static QHash enumStreamersByName = createEnumStreamersByName(); + return enumStreamersByName; +} + +QHash Bitstream::createEnumStreamersByName() { + QHash enumStreamersByName; + foreach (const TypeStreamer* streamer, getEnumStreamers()) { + enumStreamersByName.insert(streamer->getName(), streamer); + } return enumStreamersByName; } @@ -1462,17 +1470,21 @@ QDebug& operator<<(QDebug& debug, const QMetaObject* metaObject) { return debug << (metaObject ? metaObject->className() : "null"); } +EnumTypeStreamer::EnumTypeStreamer(const QMetaObject* metaObject, const char* name) : + _metaObject(metaObject), + _enumName(name), + _name(QByteArray(metaObject->className()) + "::" + name), + _bits(-1) { + + setType(QMetaType::Int); +} + EnumTypeStreamer::EnumTypeStreamer(const QMetaEnum& metaEnum) : + _name(QByteArray(metaEnum.scope()) + "::" + metaEnum.name()), _metaEnum(metaEnum), - _name(getEnumName(metaEnum)) { - - setType(QMetaType::Int); - - int highestValue = 0; - for (int j = 0; j < metaEnum.keyCount(); j++) { - highestValue = qMax(highestValue, metaEnum.value(j)); - } - _bits = getBitsForHighestValue(highestValue); + _bits(-1) { + + setType(QMetaType::Int); } const char* EnumTypeStreamer::getName() const { @@ -1484,10 +1496,21 @@ TypeReader::Type EnumTypeStreamer::getReaderType() const { } int EnumTypeStreamer::getBits() const { + if (_bits == -1) { + int highestValue = 0; + QMetaEnum metaEnum = getMetaEnum(); + for (int j = 0; j < metaEnum.keyCount(); j++) { + highestValue = qMax(highestValue, metaEnum.value(j)); + } + const_cast(this)->_bits = getBitsForHighestValue(highestValue); + } return _bits; } QMetaEnum EnumTypeStreamer::getMetaEnum() const { + if (!_metaEnum.isValid()) { + const_cast(this)->_metaEnum = _metaObject->enumerator(_metaObject->indexOfEnumerator(_enumName)); + } return _metaEnum; } @@ -1497,12 +1520,12 @@ bool EnumTypeStreamer::equal(const QVariant& first, const QVariant& second) cons void EnumTypeStreamer::write(Bitstream& out, const QVariant& value) const { int intValue = value.toInt(); - out.write(&intValue, _bits); + out.write(&intValue, getBits()); } QVariant EnumTypeStreamer::read(Bitstream& in) const { int intValue = 0; - in.read(&intValue, _bits); + in.read(&intValue, getBits()); return intValue; } @@ -1512,7 +1535,7 @@ void EnumTypeStreamer::writeDelta(Bitstream& out, const QVariant& value, const Q out << false; } else { out << true; - out.write(&intValue, _bits); + out.write(&intValue, getBits()); } } @@ -1521,7 +1544,7 @@ void EnumTypeStreamer::readDelta(Bitstream& in, QVariant& value, const QVariant& in >> changed; if (changed) { int intValue = 0; - in.read(&intValue, _bits); + in.read(&intValue, getBits()); value = intValue; } else { value = reference; @@ -1530,17 +1553,17 @@ void EnumTypeStreamer::readDelta(Bitstream& in, QVariant& value, const QVariant& void EnumTypeStreamer::writeRawDelta(Bitstream& out, const QVariant& value, const QVariant& reference) const { int intValue = value.toInt(); - out.write(&intValue, _bits); + out.write(&intValue, getBits()); } void EnumTypeStreamer::readRawDelta(Bitstream& in, QVariant& value, const QVariant& reference) const { int intValue = 0; - in.read(&intValue, _bits); + in.read(&intValue, getBits()); value = intValue; } void EnumTypeStreamer::setEnumValue(QVariant& object, int value, const QHash& mappings) const { - if (_metaEnum.isFlag()) { + if (getMetaEnum().isFlag()) { int combined = 0; for (QHash::const_iterator it = mappings.constBegin(); it != mappings.constEnd(); it++) { if (value & it.key()) { diff --git a/libraries/metavoxels/src/Bitstream.h b/libraries/metavoxels/src/Bitstream.h index caf0adf7fc..b0c33754f9 100644 --- a/libraries/metavoxels/src/Bitstream.h +++ b/libraries/metavoxels/src/Bitstream.h @@ -427,7 +427,9 @@ private: static QMultiHash& getMetaObjectSubClasses(); static QHash& getTypeStreamers(); static QHash, const TypeStreamer*>& getEnumStreamers(); + static QHash, const TypeStreamer*> createEnumStreamers(); static QHash& getEnumStreamersByName(); + static QHash createEnumStreamersByName(); static QVector getPropertyReaders(const QMetaObject* metaObject); }; @@ -938,8 +940,9 @@ public: class EnumTypeStreamer : public TypeStreamer { public: + EnumTypeStreamer(const QMetaObject* metaObject, const char* name); EnumTypeStreamer(const QMetaEnum& metaEnum); - + virtual const char* getName() const; virtual TypeReader::Type getReaderType() const; virtual int getBits() const; @@ -955,8 +958,10 @@ public: private: - QMetaEnum _metaEnum; + const QMetaObject* _metaObject; + const char* _enumName; QByteArray _name; + QMetaEnum _metaEnum; int _bits; }; @@ -1084,14 +1089,15 @@ public: template<> inline void Bitstream::readRawDelta(S::N& value, const S::N& reference) { *this >> value; } #define IMPLEMENT_ENUM_METATYPE(S, N) \ - static int S##N##Bits = registerEnumMetaType(S::staticMetaObject.enumerator( \ - S::staticMetaObject.indexOfEnumerator(#N))); \ + static int S##N##MetaTypeId = registerEnumMetaType(&S::staticMetaObject, #N); \ Bitstream& operator<<(Bitstream& out, const S::N& obj) { \ - return out.write(&obj, S##N##Bits); \ + static int bits = Bitstream::getTypeStreamer(qMetaTypeId())->getBits(); \ + return out.write(&obj, bits); \ } \ Bitstream& operator>>(Bitstream& in, S::N& obj) { \ + static int bits = Bitstream::getTypeStreamer(qMetaTypeId())->getBits(); \ obj = (S::N)0; \ - return in.read(&obj, S##N##Bits); \ + return in.read(&obj, bits); \ } /// Registers a simple type and its streamer. @@ -1103,12 +1109,11 @@ template int registerSimpleMetaType() { } /// Registers an enum type and its streamer. -/// \return the number of bits required to stream the enum -template int registerEnumMetaType(const QMetaEnum& metaEnum) { +/// \return the metatype id +template int registerEnumMetaType(const QMetaObject* metaObject, const char* name) { int type = qRegisterMetaType(); - EnumTypeStreamer* streamer = new EnumTypeStreamer(metaEnum); - Bitstream::registerTypeStreamer(type, streamer); - return streamer->getBits(); + Bitstream::registerTypeStreamer(type, new EnumTypeStreamer(metaObject, name)); + return type; } /// Registers a streamable type and its streamer. From 384fe51937d169f4fd34d7edbf15350e9331e77b Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 6 Jun 2014 16:38:52 -0700 Subject: [PATCH 32/52] If we're going to initialize one mapping lazily, we might as well initialize some more that way. --- libraries/metavoxels/src/Bitstream.cpp | 119 ++++++++++++++----------- libraries/metavoxels/src/Bitstream.h | 13 ++- 2 files changed, 71 insertions(+), 61 deletions(-) diff --git a/libraries/metavoxels/src/Bitstream.cpp b/libraries/metavoxels/src/Bitstream.cpp index 6f4af8ed5f..d9242ad9b7 100644 --- a/libraries/metavoxels/src/Bitstream.cpp +++ b/libraries/metavoxels/src/Bitstream.cpp @@ -298,7 +298,7 @@ void Bitstream::writeRawDelta(const QObject* value, const QObject* reference) { } const QMetaObject* metaObject = value->metaObject(); _metaObjectStreamer << metaObject; - foreach (const PropertyWriter& propertyWriter, getPropertyWriters(metaObject)) { + foreach (const PropertyWriter& propertyWriter, getPropertyWriters().value(metaObject)) { propertyWriter.writeDelta(*this, value, reference); } } @@ -476,7 +476,7 @@ Bitstream& Bitstream::operator<<(const QObject* object) { } const QMetaObject* metaObject = object->metaObject(); _metaObjectStreamer << metaObject; - foreach (const PropertyWriter& propertyWriter, getPropertyWriters(metaObject)) { + foreach (const PropertyWriter& propertyWriter, getPropertyWriters().value(metaObject)) { propertyWriter.write(*this, object); } return *this; @@ -561,7 +561,7 @@ Bitstream& Bitstream::operator<(const QMetaObject* metaObject) { if (_metadataType == NO_METADATA) { return *this; } - const QVector& propertyWriters = getPropertyWriters(metaObject); + const QVector& propertyWriters = getPropertyWriters().value(metaObject); *this << propertyWriters.size(); QCryptographicHash hash(QCryptographicHash::Md5); foreach (const PropertyWriter& propertyWriter, propertyWriters) { @@ -595,7 +595,7 @@ Bitstream& Bitstream::operator>(ObjectReader& objectReader) { qWarning() << "Unknown class name: " << className << "\n"; } if (_metadataType == NO_METADATA) { - objectReader = ObjectReader(className, metaObject, getPropertyReaders(metaObject)); + objectReader = ObjectReader(className, metaObject, getPropertyReaders().value(metaObject)); return *this; } int storedPropertyCount; @@ -619,7 +619,7 @@ Bitstream& Bitstream::operator>(ObjectReader& objectReader) { QCryptographicHash hash(QCryptographicHash::Md5); bool matches = true; if (metaObject) { - const QVector& propertyWriters = getPropertyWriters(metaObject); + const QVector& propertyWriters = getPropertyWriters().value(metaObject); if (propertyWriters.size() == properties.size()) { for (int i = 0; i < propertyWriters.size(); i++) { const PropertyWriter& propertyWriter = propertyWriters.at(i); @@ -638,7 +638,7 @@ Bitstream& Bitstream::operator>(ObjectReader& objectReader) { QByteArray remoteHashResult(localHashResult.size(), 0); read(remoteHashResult.data(), remoteHashResult.size() * BITS_IN_BYTE); if (metaObject && matches && localHashResult == remoteHashResult) { - objectReader = ObjectReader(className, metaObject, getPropertyReaders(metaObject)); + objectReader = ObjectReader(className, metaObject, getPropertyReaders().value(metaObject)); return *this; } } @@ -975,31 +975,6 @@ void Bitstream::clearSharedObject(QObject* object) { } } -const QVector& Bitstream::getPropertyWriters(const QMetaObject* metaObject) { - QVector& propertyWriters = _propertyWriters[metaObject]; - if (propertyWriters.isEmpty()) { - for (int i = 0; i < metaObject->propertyCount(); i++) { - QMetaProperty property = metaObject->property(i); - if (!property.isStored()) { - continue; - } - const TypeStreamer* streamer; - if (property.isEnumType()) { - QMetaEnum metaEnum = property.enumerator(); - streamer = getEnumStreamers().value(QPair( - QByteArray::fromRawData(metaEnum.scope(), strlen(metaEnum.scope())), - QByteArray::fromRawData(metaEnum.name(), strlen(metaEnum.name())))); - } else { - streamer = getTypeStreamers().value(property.userType()); - } - if (streamer) { - propertyWriters.append(PropertyWriter(property, streamer)); - } - } - } - return propertyWriters; -} - QHash& Bitstream::getMetaObjects() { static QHash metaObjects; return metaObjects; @@ -1015,7 +990,7 @@ QHash& Bitstream::getTypeStreamers() { return typeStreamers; } -QHash, const TypeStreamer*>& Bitstream::getEnumStreamers() { +const QHash, const TypeStreamer*>& Bitstream::getEnumStreamers() { static QHash, const TypeStreamer*> enumStreamers = createEnumStreamers(); return enumStreamers; } @@ -1034,7 +1009,7 @@ QHash, const TypeStreamer*> Bitstream::createEnumS return enumStreamers; } -QHash& Bitstream::getEnumStreamersByName() { +const QHash& Bitstream::getEnumStreamersByName() { static QHash enumStreamersByName = createEnumStreamersByName(); return enumStreamersByName; } @@ -1047,32 +1022,68 @@ QHash Bitstream::createEnumStreamersByName() { return enumStreamersByName; } -QVector Bitstream::getPropertyReaders(const QMetaObject* metaObject) { - QVector propertyReaders; - if (!metaObject) { - return propertyReaders; - } - for (int i = 0; i < metaObject->propertyCount(); i++) { - QMetaProperty property = metaObject->property(i); - if (!property.isStored()) { - continue; - } - const TypeStreamer* streamer; - if (property.isEnumType()) { - QMetaEnum metaEnum = property.enumerator(); - streamer = getEnumStreamers().value(QPair( - QByteArray::fromRawData(metaEnum.scope(), strlen(metaEnum.scope())), - QByteArray::fromRawData(metaEnum.name(), strlen(metaEnum.name())))); - } else { - streamer = getTypeStreamers().value(property.userType()); - } - if (streamer) { - propertyReaders.append(PropertyReader(TypeReader(QByteArray(), streamer), property)); +const QHash >& Bitstream::getPropertyReaders() { + static QHash > propertyReaders = createPropertyReaders(); + return propertyReaders; +} + +QHash > Bitstream::createPropertyReaders() { + QHash > propertyReaders; + foreach (const QMetaObject* metaObject, getMetaObjects()) { + QVector& readers = propertyReaders[metaObject]; + for (int i = 0; i < metaObject->propertyCount(); i++) { + QMetaProperty property = metaObject->property(i); + if (!property.isStored()) { + continue; + } + const TypeStreamer* streamer; + if (property.isEnumType()) { + QMetaEnum metaEnum = property.enumerator(); + streamer = getEnumStreamers().value(QPair( + QByteArray::fromRawData(metaEnum.scope(), strlen(metaEnum.scope())), + QByteArray::fromRawData(metaEnum.name(), strlen(metaEnum.name())))); + } else { + streamer = getTypeStreamers().value(property.userType()); + } + if (streamer) { + readers.append(PropertyReader(TypeReader(QByteArray(), streamer), property)); + } } } return propertyReaders; } +const QHash >& Bitstream::getPropertyWriters() { + static QHash > propertyWriters = createPropertyWriters(); + return propertyWriters; +} + +QHash > Bitstream::createPropertyWriters() { + QHash > propertyWriters; + foreach (const QMetaObject* metaObject, getMetaObjects()) { + QVector& writers = propertyWriters[metaObject]; + for (int i = 0; i < metaObject->propertyCount(); i++) { + QMetaProperty property = metaObject->property(i); + if (!property.isStored()) { + continue; + } + const TypeStreamer* streamer; + if (property.isEnumType()) { + QMetaEnum metaEnum = property.enumerator(); + streamer = getEnumStreamers().value(QPair( + QByteArray::fromRawData(metaEnum.scope(), strlen(metaEnum.scope())), + QByteArray::fromRawData(metaEnum.name(), strlen(metaEnum.name())))); + } else { + streamer = getTypeStreamers().value(property.userType()); + } + if (streamer) { + writers.append(PropertyWriter(property, streamer)); + } + } + } + return propertyWriters; +} + TypeReader::TypeReader(const QByteArray& typeName, const TypeStreamer* streamer) : _typeName(typeName), _streamer(streamer), diff --git a/libraries/metavoxels/src/Bitstream.h b/libraries/metavoxels/src/Bitstream.h index b0c33754f9..80adfc4e8b 100644 --- a/libraries/metavoxels/src/Bitstream.h +++ b/libraries/metavoxels/src/Bitstream.h @@ -400,8 +400,6 @@ private slots: private: - const QVector& getPropertyWriters(const QMetaObject* metaObject); - QDataStream& _underlying; quint8 _byte; int _position; @@ -421,16 +419,17 @@ private: QHash _metaObjectSubstitutions; QHash _typeStreamerSubstitutions; - QHash > _propertyWriters; - static QHash& getMetaObjects(); static QMultiHash& getMetaObjectSubClasses(); static QHash& getTypeStreamers(); - static QHash, const TypeStreamer*>& getEnumStreamers(); + static const QHash, const TypeStreamer*>& getEnumStreamers(); static QHash, const TypeStreamer*> createEnumStreamers(); - static QHash& getEnumStreamersByName(); + static const QHash& getEnumStreamersByName(); static QHash createEnumStreamersByName(); - static QVector getPropertyReaders(const QMetaObject* metaObject); + static const QHash >& getPropertyReaders(); + static QHash > createPropertyReaders(); + static const QHash >& getPropertyWriters(); + static QHash > createPropertyWriters(); }; template inline void Bitstream::writeDelta(const T& value, const T& reference) { From b39559d86086f3b78fff66e5476553c315ba9a28 Mon Sep 17 00:00:00 2001 From: wangyix Date: Fri, 6 Jun 2014 17:44:30 -0700 Subject: [PATCH 33/52] packet recovery seems to be working Seems to impact FPS a lot. OctreeSceneStats is not being locked (causes freezing, need to find out why). --- .../src/octree/OctreeQueryNode.cpp | 5 --- .../src/octree/OctreeQueryNode.h | 4 ++- .../src/octree/OctreeSendThread.cpp | 3 +- assignment-client/src/octree/OctreeServer.cpp | 35 ++++++++++--------- interface/src/Application.cpp | 16 +++++---- libraries/networking/src/LimitedNodeList.cpp | 4 +-- libraries/networking/src/PacketHeaders.h | 3 +- 7 files changed, 37 insertions(+), 33 deletions(-) diff --git a/assignment-client/src/octree/OctreeQueryNode.cpp b/assignment-client/src/octree/OctreeQueryNode.cpp index 208be5951b..cf01e9a864 100644 --- a/assignment-client/src/octree/OctreeQueryNode.cpp +++ b/assignment-client/src/octree/OctreeQueryNode.cpp @@ -377,11 +377,6 @@ void OctreeQueryNode::packetSent(const QByteArray& packet) { _sequenceNumber++; } - -void OctreeQueryNode::addSequenceNumbersToResend(const QList& sequenceNumbers) { - _nackedSequenceNumbers.append(sequenceNumbers); -} - bool OctreeQueryNode::hasNextNackedPacket() const { return !_nackedSequenceNumbers.isEmpty(); } diff --git a/assignment-client/src/octree/OctreeQueryNode.h b/assignment-client/src/octree/OctreeQueryNode.h index e1707cc899..b79367503c 100644 --- a/assignment-client/src/octree/OctreeQueryNode.h +++ b/assignment-client/src/octree/OctreeQueryNode.h @@ -109,7 +109,9 @@ public: OCTREE_PACKET_SEQUENCE getSequenceNumber() const { return _sequenceNumber; } - void addSequenceNumbersToResend(const QList& sequenceNumbers); + void addNackedSequenceNumber(OCTREE_PACKET_SEQUENCE sequenceNumber) { + _nackedSequenceNumbers.append(sequenceNumber); + } bool hasNextNackedPacket() const; const QByteArray* getNextNackedPacket(); diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index e5c47f5d2d..cb8a773a64 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -305,7 +305,8 @@ int OctreeSendThread::resendNackedPackets(OctreeQueryNode* nodeData) { _totalWastedBytes += MAX_PACKET_SIZE - packet->size(); // ??? } } - + +if (packetsSent > 0) printf("\t\t re-sent %d packets!\n", packetsSent); return packetsSent; } diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index 46eb7aac16..8cf1649cdb 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -832,10 +832,9 @@ void OctreeServer::readPendingDatagrams() { PacketType packetType = packetTypeForPacket(receivedPacket); SharedNodePointer matchingNode = nodeList->sendingNodeForPacket(receivedPacket); if (packetType == getMyQueryMessageType()) { - // If we got a query packet, then we're talking to an agent, and we // need to make sure we have it in our nodeList. - if (matchingNode) { + if (matchingNode) { nodeList->updateNodeWithDataFromPacket(matchingNode, receivedPacket); OctreeQueryNode* nodeData = (OctreeQueryNode*)matchingNode->getLinkedData(); if (nodeData && !nodeData->isOctreeSendThreadInitalized()) { @@ -852,25 +851,29 @@ void OctreeServer::readPendingDatagrams() { } else if (packetType == PacketTypeOctreeDataNack) { // parse packet for sequence numbers that need to be resent -int numBytesPacketHeader = numBytesForPacketHeader(receivedPacket); -const unsigned char* dataAt = reinterpret_cast(receivedPacket.data()) + numBytesPacketHeader; -uint16_t numSequenceNumbers = (*(uint16_t*)dataAt); -dataAt += sizeof(uint16_t); +if (matchingNode) { -// read sequence numbers -QList sequenceNumbers; -for (int i = 0; i < numSequenceNumbers; i++) { - OCTREE_PACKET_SEQUENCE sequenceNumber = (*(OCTREE_PACKET_SEQUENCE*)dataAt); - sequenceNumbers.append(sequenceNumber); - dataAt += sizeof(OCTREE_PACKET_SEQUENCE); + OctreeQueryNode* nodeData = (OctreeQueryNode*)matchingNode->getLinkedData(); -printf("\t\t\t nacked packet: seq = %d\n", sequenceNumber); + int numBytesPacketHeader = numBytesForPacketHeader(receivedPacket); + const unsigned char* dataAt = reinterpret_cast(receivedPacket.data()) + numBytesPacketHeader; + + uint16_t numSequenceNumbers = (*(uint16_t*)dataAt); + dataAt += sizeof(uint16_t); + +printf("\t received nack packet containing %d seq nums\n", numSequenceNumbers); + + // read sequence numbers + for (int i = 0; i < numSequenceNumbers; i++) { + OCTREE_PACKET_SEQUENCE sequenceNumber = (*(OCTREE_PACKET_SEQUENCE*)dataAt); + nodeData->addNackedSequenceNumber(sequenceNumber); + dataAt += sizeof(OCTREE_PACKET_SEQUENCE); + +printf("\t seq = %d\n", sequenceNumber); + } } -OctreeQueryNode* nodeData = (OctreeQueryNode*)matchingNode->getLinkedData(); // move this or something -nodeData->addSequenceNumbersToResend(sequenceNumbers); - } else if (packetType == PacketTypeJurisdictionRequest) { diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 07bef852f2..a28343eb96 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2110,8 +2110,6 @@ void Application::updateMyAvatar(float deltaTime) { void Application::sendNack() { -printf("\n\t sendNack()...\n"); - char packet[MAX_PACKET_SIZE]; NodeList* nodeList = NodeList::getInstance(); @@ -2124,15 +2122,18 @@ printf("\n\t sendNack()...\n"); || node->getType() == NodeType::ModelServer) ) { - _octreeSceneStatsLock.lockForWrite(); + //_octreeSceneStatsLock.lockForWrite(); OctreeSceneStats& stats = _octreeServerSceneStats[node->getUUID()]; + int numSequenceNumbersAvailable = stats.getNumSequenceNumbersToNack(); + if (numSequenceNumbersAvailable == 0) + continue; char* dataAt = packet; int bytesRemaining = MAX_PACKET_SIZE; // pack header - int numBytesPacketHeader = populatePacketHeader(packet, PacketTypeOctreeDataNack, node->getUUID()); + int numBytesPacketHeader = populatePacketHeader(packet, PacketTypeOctreeDataNack); dataAt += numBytesPacketHeader; bytesRemaining -= numBytesPacketHeader; @@ -2140,12 +2141,13 @@ printf("\n\t sendNack()...\n"); // calculate and pack number of sequence numbers - uint16_t numSequenceNumbers = min(stats.getNumSequenceNumbersToNack(), numPacketsRoomFor); + uint16_t numSequenceNumbers = min(numSequenceNumbersAvailable, numPacketsRoomFor); uint16_t* numSequenceNumbersAt = (uint16_t*)dataAt; *numSequenceNumbersAt = numSequenceNumbers; dataAt += sizeof(uint16_t); // pack sequence numbers +printf("\n\t sending nack...\n"); printf("\t\t packed %d seq #s:", numSequenceNumbers); for (int i = 0; i < numSequenceNumbers; i++) { OCTREE_PACKET_SEQUENCE* sequenceNumberAt = (OCTREE_PACKET_SEQUENCE*)dataAt; @@ -2155,10 +2157,10 @@ printf(" %d,", *sequenceNumberAt); } printf("\n"); - _octreeSceneStatsLock.unlock(); + //_octreeSceneStatsLock.unlock(); // make sure we still have an active socket???? - nodeList->writeUnverifiedDatagram(packet, dataAt - packet, node); + nodeList->writeUnverifiedDatagram(packet, dataAt-packet, node); } } } diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index f9630c9102..15cebc26ac 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -274,13 +274,13 @@ qint64 LimitedNodeList::writeDatagram(const char* data, qint64 size, const Share qint64 LimitedNodeList::writeDatagram2(int seq, const char* data, qint64 size, const SharedNodePointer& destinationNode, const HifiSockAddr& overridenSockAddr) { - qint64 ret; + qint64 ret = -1; if (randFloat() < 0.8f) { ret = writeDatagram(QByteArray(data, size), destinationNode, overridenSockAddr); } else { - printf("\t\t\t dropped packet seq = %d!!!\n", seq); + printf("dropped packet seq = %d --------------------------\n", seq); } diff --git a/libraries/networking/src/PacketHeaders.h b/libraries/networking/src/PacketHeaders.h index a73ffe8564..eac2f88870 100644 --- a/libraries/networking/src/PacketHeaders.h +++ b/libraries/networking/src/PacketHeaders.h @@ -75,7 +75,8 @@ const QSet NON_VERIFIED_PACKETS = QSet() << PacketTypeDomainServerRequireDTLS << PacketTypeDomainConnectRequest << PacketTypeDomainList << PacketTypeDomainListRequest << PacketTypeDomainOAuthRequest << PacketTypeCreateAssignment << PacketTypeRequestAssignment << PacketTypeStunResponse - << PacketTypeNodeJsonStats << PacketTypeVoxelQuery << PacketTypeParticleQuery << PacketTypeModelQuery; + << PacketTypeNodeJsonStats << PacketTypeVoxelQuery << PacketTypeParticleQuery << PacketTypeModelQuery +<< PacketTypeOctreeDataNack; const int NUM_BYTES_MD5_HASH = 16; const int NUM_STATIC_HEADER_BYTES = sizeof(PacketVersion) + NUM_BYTES_RFC4122_UUID; From 52860908128fe0052a18981ace38b2ec06da2a46 Mon Sep 17 00:00:00 2001 From: wangyix Date: Fri, 6 Jun 2014 17:52:48 -0700 Subject: [PATCH 34/52] removed interface print statements --- interface/src/Application.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index a28343eb96..87e82b21a2 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2147,15 +2147,15 @@ void Application::sendNack() { dataAt += sizeof(uint16_t); // pack sequence numbers -printf("\n\t sending nack...\n"); -printf("\t\t packed %d seq #s:", numSequenceNumbers); +//printf("\n\t sending nack...\n"); +//printf("\t\t packed %d seq #s:", numSequenceNumbers); for (int i = 0; i < numSequenceNumbers; i++) { OCTREE_PACKET_SEQUENCE* sequenceNumberAt = (OCTREE_PACKET_SEQUENCE*)dataAt; *sequenceNumberAt = stats.getNextSequenceNumberToNack(); dataAt += sizeof(OCTREE_PACKET_SEQUENCE); -printf(" %d,", *sequenceNumberAt); +//printf(" %d,", *sequenceNumberAt); } -printf("\n"); +//printf("\n"); //_octreeSceneStatsLock.unlock(); From 6eac0ee2aeb262feee7a192b17c786c933e1d8db Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 9 Jun 2014 10:58:56 -0700 Subject: [PATCH 35/52] Avoid crash on zero-length normals. --- libraries/fbx/src/FBXReader.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/libraries/fbx/src/FBXReader.cpp b/libraries/fbx/src/FBXReader.cpp index 60412cf0ce..d668349b96 100644 --- a/libraries/fbx/src/FBXReader.cpp +++ b/libraries/fbx/src/FBXReader.cpp @@ -894,14 +894,19 @@ FBXBlendshape extractBlendshape(const FBXNode& object) { } void setTangents(FBXMesh& mesh, int firstIndex, int secondIndex) { - glm::vec3 normal = glm::normalize(mesh.normals.at(firstIndex)); - glm::vec3 bitangent = glm::cross(normal, mesh.vertices.at(secondIndex) - mesh.vertices.at(firstIndex)); + const glm::vec3& normal = mesh.normals.at(firstIndex); + float normalLength = glm::length(normal); + if (normalLength < EPSILON) { + return; + } + glm::vec3 normalizedNormal = normal / normalLength; + glm::vec3 bitangent = glm::cross(normalizedNormal, mesh.vertices.at(secondIndex) - mesh.vertices.at(firstIndex)); if (glm::length(bitangent) < EPSILON) { return; } glm::vec2 texCoordDelta = mesh.texCoords.at(secondIndex) - mesh.texCoords.at(firstIndex); - mesh.tangents[firstIndex] += glm::cross(glm::angleAxis( - - atan2f(-texCoordDelta.t, texCoordDelta.s), normal) * glm::normalize(bitangent), normal); + mesh.tangents[firstIndex] += glm::cross(glm::angleAxis(-atan2f(-texCoordDelta.t, texCoordDelta.s), normalizedNormal) * + glm::normalize(bitangent), normalizedNormal); } QVector getIndices(const QVector ids, QVector modelIDs) { From a1e208ae3d3173ca4490a9d96941e860adf9e0b0 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 9 Jun 2014 11:03:50 -0700 Subject: [PATCH 36/52] Simplification. If the normal is zero, then the cross product will also be zero, so we can just have the one check and postpone normalization until afterwards. --- libraries/fbx/src/FBXReader.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/libraries/fbx/src/FBXReader.cpp b/libraries/fbx/src/FBXReader.cpp index d668349b96..9aeb81a2a3 100644 --- a/libraries/fbx/src/FBXReader.cpp +++ b/libraries/fbx/src/FBXReader.cpp @@ -895,16 +895,12 @@ FBXBlendshape extractBlendshape(const FBXNode& object) { void setTangents(FBXMesh& mesh, int firstIndex, int secondIndex) { const glm::vec3& normal = mesh.normals.at(firstIndex); - float normalLength = glm::length(normal); - if (normalLength < EPSILON) { - return; - } - glm::vec3 normalizedNormal = normal / normalLength; - glm::vec3 bitangent = glm::cross(normalizedNormal, mesh.vertices.at(secondIndex) - mesh.vertices.at(firstIndex)); + glm::vec3 bitangent = glm::cross(normal, mesh.vertices.at(secondIndex) - mesh.vertices.at(firstIndex)); if (glm::length(bitangent) < EPSILON) { return; } glm::vec2 texCoordDelta = mesh.texCoords.at(secondIndex) - mesh.texCoords.at(firstIndex); + glm::vec3 normalizedNormal = glm::normalize(normal); mesh.tangents[firstIndex] += glm::cross(glm::angleAxis(-atan2f(-texCoordDelta.t, texCoordDelta.s), normalizedNormal) * glm::normalize(bitangent), normalizedNormal); } From 3bc457d4d2ea981f3c12bb8605bfe078f9c180bf Mon Sep 17 00:00:00 2001 From: wangyix Date: Mon, 9 Jun 2014 11:14:02 -0700 Subject: [PATCH 37/52] added octree scene stats locking and unlocking --- .../src/octree/OctreeQueryNode.cpp | 8 +-- .../src/octree/OctreeSendThread.cpp | 3 - interface/src/Application.cpp | 69 ++++++++++++------- libraries/octree/src/OctreeSceneStats.h | 4 +- 4 files changed, 49 insertions(+), 35 deletions(-) diff --git a/assignment-client/src/octree/OctreeQueryNode.cpp b/assignment-client/src/octree/OctreeQueryNode.cpp index cf01e9a864..5cfe5501e1 100644 --- a/assignment-client/src/octree/OctreeQueryNode.cpp +++ b/assignment-client/src/octree/OctreeQueryNode.cpp @@ -382,11 +382,9 @@ bool OctreeQueryNode::hasNextNackedPacket() const { } const QByteArray* OctreeQueryNode::getNextNackedPacket() { - if (!_nackedSequenceNumbers.isEmpty()) { - const QByteArray* nextPacket = _sentPacketHistory.getPacket(_nackedSequenceNumbers.first()); - _nackedSequenceNumbers.pop_front(); - return nextPacket; // could be null + // could return null if packet is not in the history + return _sentPacketHistory.getPacket(_nackedSequenceNumbers.takeFirst()); } return NULL; -} \ No newline at end of file +} diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index cb8a773a64..6f39cd28dc 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -288,18 +288,15 @@ NodeList::getInstance()->writeDatagram2(nodeData->getSequenceNumber(), (char*)no int OctreeSendThread::resendNackedPackets(OctreeQueryNode* nodeData) { const int MAX_PACKETS_RESEND = 10; - int packetsSent = 0; const QByteArray* packet; while (nodeData->hasNextNackedPacket() && packetsSent < MAX_PACKETS_RESEND) { packet = nodeData->getNextNackedPacket(); - // packet will be NULL if it's not in nodeData's packet history if (packet) { NodeList::getInstance()->writeDatagram(*packet, _node); packetsSent++; - // ?????? _totalBytes += packet->size(); _totalPackets++; _totalWastedBytes += MAX_PACKET_SIZE - packet->size(); // ??? diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 87e82b21a2..f8152bb62b 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2107,6 +2107,21 @@ void Application::updateMyAvatar(float deltaTime) { } } +/*/ Attempt to identify the sender from it's address. + if (sendingNode) { + QUuid nodeUUID = sendingNode->getUUID(); + + // now that we know the node ID, let's add these stats to the stats for that node... + _octreeSceneStatsLock.lockForWrite(); + if (_octreeServerSceneStats.find(nodeUUID) != _octreeServerSceneStats.end()) { + OctreeSceneStats& stats = _octreeServerSceneStats[nodeUUID]; + stats.trackIncomingOctreePacket(packet, wasStatsPacket, sendingNode->getClockSkewUsec()); + } + _octreeSceneStatsLock.unlock(); + } + */ + + void Application::sendNack() { @@ -2122,13 +2137,6 @@ void Application::sendNack() { || node->getType() == NodeType::ModelServer) ) { - //_octreeSceneStatsLock.lockForWrite(); - - OctreeSceneStats& stats = _octreeServerSceneStats[node->getUUID()]; - int numSequenceNumbersAvailable = stats.getNumSequenceNumbersToNack(); - if (numSequenceNumbersAvailable == 0) - continue; - char* dataAt = packet; int bytesRemaining = MAX_PACKET_SIZE; @@ -2136,28 +2144,39 @@ void Application::sendNack() { int numBytesPacketHeader = populatePacketHeader(packet, PacketTypeOctreeDataNack); dataAt += numBytesPacketHeader; bytesRemaining -= numBytesPacketHeader; - - int numPacketsRoomFor = (bytesRemaining - sizeof(uint16_t)) / sizeof(OCTREE_PACKET_SEQUENCE); + int numSequenceNumbersRoomFor = (bytesRemaining - sizeof(uint16_t)) / sizeof(OCTREE_PACKET_SEQUENCE); - // calculate and pack number of sequence numbers - uint16_t numSequenceNumbers = min(numSequenceNumbersAvailable, numPacketsRoomFor); - uint16_t* numSequenceNumbersAt = (uint16_t*)dataAt; - *numSequenceNumbersAt = numSequenceNumbers; - dataAt += sizeof(uint16_t); + QUuid nodeUUID = node->getUUID(); - // pack sequence numbers -//printf("\n\t sending nack...\n"); -//printf("\t\t packed %d seq #s:", numSequenceNumbers); - for (int i = 0; i < numSequenceNumbers; i++) { - OCTREE_PACKET_SEQUENCE* sequenceNumberAt = (OCTREE_PACKET_SEQUENCE*)dataAt; - *sequenceNumberAt = stats.getNextSequenceNumberToNack(); - dataAt += sizeof(OCTREE_PACKET_SEQUENCE); -//printf(" %d,", *sequenceNumberAt); + _octreeSceneStatsLock.lockForWrite(); + if (_octreeServerSceneStats.find(nodeUUID) != _octreeServerSceneStats.end()) { + OctreeSceneStats& stats = _octreeServerSceneStats[nodeUUID]; + + int numSequenceNumbersAvailable = stats.getNumSequenceNumbersToNack(); + if (numSequenceNumbersAvailable == 0) { + _octreeSceneStatsLock.unlock(); + continue; + } + + // calculate and pack 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 + //printf("\n\t sending nack...\n"); + //printf("\t\t packed %d seq #s:", numSequenceNumbers); + for (int i = 0; i < numSequenceNumbers; i++) { + OCTREE_PACKET_SEQUENCE* sequenceNumberAt = (OCTREE_PACKET_SEQUENCE*)dataAt; + *sequenceNumberAt = stats.getNextSequenceNumberToNack(); + dataAt += sizeof(OCTREE_PACKET_SEQUENCE); + //printf(" %d,", *sequenceNumberAt); + } + //printf("\n"); } -//printf("\n"); - - //_octreeSceneStatsLock.unlock(); + _octreeSceneStatsLock.unlock(); // make sure we still have an active socket???? nodeList->writeUnverifiedDatagram(packet, dataAt-packet, node); diff --git a/libraries/octree/src/OctreeSceneStats.h b/libraries/octree/src/OctreeSceneStats.h index ca9bf7c74b..ac9b1606c1 100644 --- a/libraries/octree/src/OctreeSceneStats.h +++ b/libraries/octree/src/OctreeSceneStats.h @@ -275,8 +275,8 @@ private: quint32 _incomingLate; /// out of order later than expected quint32 _incomingReallyLate; /// out of order and later than MAX_MISSING_SEQUENCE_OLD_AGE late quint32 _incomingPossibleDuplicate; /// out of order possibly a duplicate - QSet _missingSequenceNumbers; -QSet _sequenceNumbersToNack; + QSet _missingSequenceNumbers; +QSet _sequenceNumbersToNack; SimpleMovingAverage _incomingFlightTimeAverage; // features related items From 936f04cececd2e29177d9189f25487e623ff7240 Mon Sep 17 00:00:00 2001 From: barnold1953 Date: Mon, 9 Jun 2014 11:55:29 -0700 Subject: [PATCH 38/52] Simple raypicking for scripts with oculus rift. --- interface/src/Camera.cpp | 8 +++++++- interface/src/ui/ApplicationOverlay.cpp | 21 +++++++++++++++++++-- interface/src/ui/ApplicationOverlay.h | 3 ++- 3 files changed, 28 insertions(+), 4 deletions(-) diff --git a/interface/src/Camera.cpp b/interface/src/Camera.cpp index f9ee5bdd25..0e33e14f32 100644 --- a/interface/src/Camera.cpp +++ b/interface/src/Camera.cpp @@ -18,6 +18,7 @@ #include "Camera.h" #include "Menu.h" #include "Util.h" +#include "devices/OculusManager.h" const float CAMERA_FIRST_PERSON_MODE_UP_SHIFT = 0.0f; const float CAMERA_FIRST_PERSON_MODE_DISTANCE = 0.0f; @@ -264,7 +265,12 @@ PickRay CameraScriptableObject::computePickRay(float x, float y) { float screenWidth = Application::getInstance()->getGLWidget()->width(); float screenHeight = Application::getInstance()->getGLWidget()->height(); PickRay result; - _viewFrustum->computePickRay(x / screenWidth, y / screenHeight, result.origin, result.direction); + if (OculusManager::isConnected()) { + result.origin = _camera->getPosition(); + Application::getInstance()->getApplicationOverlay().computeOculusPickRay(x / screenWidth, y / screenHeight, result.direction); + } else { + _viewFrustum->computePickRay(x / screenWidth, y / screenHeight, result.origin, result.direction); + } return result; } diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index 49ec8ecddb..f5de7459a8 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -297,6 +297,25 @@ void ApplicationOverlay::displayOverlayTexture(Camera& whichCamera) { glDisable(GL_TEXTURE_2D); } +const float textureFov = PI / 2.5f; + +void ApplicationOverlay::computeOculusPickRay(float x, float y, glm::vec3& direction) const { + glm::quat rot = Application::getInstance()->getAvatar()->getOrientation(); + + //invert y direction + y = 1.0 - y; + + //Get position on hemisphere UI + x = sin((x - 0.5f) * textureFov); + y = sin((y - 0.5f) * textureFov); + + float dist = sqrt(x * x + y * y); + float z = -sqrt(1.0f - dist * dist); + + //Rotate the UI pick ray by the avatar orientation + direction = glm::normalize(rot * glm::vec3(x, y, z)); +} + // Fast helper functions inline float max(float a, float b) { return (a > b) ? a : b; @@ -306,8 +325,6 @@ inline float min(float a, float b) { return (a < b) ? a : b; } -const float textureFov = PI / 2.5f; - // Draws the FBO texture for Oculus rift. TODO: Draw a curved texture instead of plane. void ApplicationOverlay::displayOverlayTextureOculus(Camera& whichCamera) { diff --git a/interface/src/ui/ApplicationOverlay.h b/interface/src/ui/ApplicationOverlay.h index 8817549277..1bf0e18816 100644 --- a/interface/src/ui/ApplicationOverlay.h +++ b/interface/src/ui/ApplicationOverlay.h @@ -15,7 +15,7 @@ class Overlays; class QOpenGLFramebufferObject; -// Handles the drawing of the overlays to the scree +// Handles the drawing of the overlays to the screen class ApplicationOverlay { public: @@ -27,6 +27,7 @@ public: void renderOverlay(bool renderToTexture = false); void displayOverlayTexture(Camera& whichCamera); void displayOverlayTextureOculus(Camera& whichCamera); + void computeOculusPickRay(float x, float y, glm::vec3& direction) const; // Getters QOpenGLFramebufferObject* getFramebufferObject(); From 529dd827a2d613aa6c6b3fd74d9dfcbeaf9de72e Mon Sep 17 00:00:00 2001 From: wangyix Date: Mon, 9 Jun 2014 12:00:19 -0700 Subject: [PATCH 39/52] moved around code in sendNack() a bit --- interface/src/Application.cpp | 65 ++++++++++++---------- libraries/networking/src/PacketHeaders.cpp | 2 +- libraries/octree/src/OctreeSceneStats.h | 4 +- 3 files changed, 38 insertions(+), 33 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index f8152bb62b..3ebfe728de 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2137,6 +2137,25 @@ void Application::sendNack() { || node->getType() == NodeType::ModelServer) ) { + QUuid nodeUUID = node->getUUID(); + + + _octreeSceneStatsLock.lockForWrite(); + + // retreive octree scene stats of this node + if (_octreeServerSceneStats.find(nodeUUID) == _octreeServerSceneStats.end()) { + _octreeSceneStatsLock.unlock(); + continue; + } + 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; + } + char* dataAt = packet; int bytesRemaining = MAX_PACKET_SIZE; @@ -2146,40 +2165,26 @@ void Application::sendNack() { 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); - QUuid nodeUUID = node->getUUID(); - - _octreeSceneStatsLock.lockForWrite(); - if (_octreeServerSceneStats.find(nodeUUID) != _octreeServerSceneStats.end()) { - OctreeSceneStats& stats = _octreeServerSceneStats[nodeUUID]; - - int numSequenceNumbersAvailable = stats.getNumSequenceNumbersToNack(); - if (numSequenceNumbersAvailable == 0) { - _octreeSceneStatsLock.unlock(); - continue; - } - - // calculate and pack 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 - //printf("\n\t sending nack...\n"); - //printf("\t\t packed %d seq #s:", numSequenceNumbers); - for (int i = 0; i < numSequenceNumbers; i++) { - OCTREE_PACKET_SEQUENCE* sequenceNumberAt = (OCTREE_PACKET_SEQUENCE*)dataAt; - *sequenceNumberAt = stats.getNextSequenceNumberToNack(); - dataAt += sizeof(OCTREE_PACKET_SEQUENCE); - //printf(" %d,", *sequenceNumberAt); - } - //printf("\n"); + // pack sequence numbers +//printf("\n\t sending nack...\n"); +//printf("\t\t packed %d seq #s:", numSequenceNumbers); + for (int i = 0; i < numSequenceNumbers; i++) { + OCTREE_PACKET_SEQUENCE* sequenceNumberAt = (OCTREE_PACKET_SEQUENCE*)dataAt; + *sequenceNumberAt = stats.getNextSequenceNumberToNack(); + dataAt += sizeof(OCTREE_PACKET_SEQUENCE); +//printf(" %d,", *sequenceNumberAt); } +//printf("\n"); + _octreeSceneStatsLock.unlock(); - // make sure we still have an active socket???? - nodeList->writeUnverifiedDatagram(packet, dataAt-packet, node); + nodeList->writeUnverifiedDatagram(packet, dataAt - packet, node); } } } diff --git a/libraries/networking/src/PacketHeaders.cpp b/libraries/networking/src/PacketHeaders.cpp index 7278f1fbcb..e2bc46b3be 100644 --- a/libraries/networking/src/PacketHeaders.cpp +++ b/libraries/networking/src/PacketHeaders.cpp @@ -108,7 +108,7 @@ int populatePacketHeader(char* packet, PacketType type, const QUuid& connectionU position += NUM_BYTES_RFC4122_UUID; if (!NON_VERIFIED_PACKETS.contains(type)) { - // pack 16 bytes of zeros where the md5 hash will be placed one data is packed + // pack 16 bytes of zeros where the md5 hash will be placed once data is packed memset(position, 0, NUM_BYTES_MD5_HASH); position += NUM_BYTES_MD5_HASH; } diff --git a/libraries/octree/src/OctreeSceneStats.h b/libraries/octree/src/OctreeSceneStats.h index ac9b1606c1..ca9bf7c74b 100644 --- a/libraries/octree/src/OctreeSceneStats.h +++ b/libraries/octree/src/OctreeSceneStats.h @@ -275,8 +275,8 @@ private: quint32 _incomingLate; /// out of order later than expected quint32 _incomingReallyLate; /// out of order and later than MAX_MISSING_SEQUENCE_OLD_AGE late quint32 _incomingPossibleDuplicate; /// out of order possibly a duplicate - QSet _missingSequenceNumbers; -QSet _sequenceNumbersToNack; + QSet _missingSequenceNumbers; +QSet _sequenceNumbersToNack; SimpleMovingAverage _incomingFlightTimeAverage; // features related items From aa694d69678d94c71d3961de068e5bf0d1a4c562 Mon Sep 17 00:00:00 2001 From: wangyix Date: Mon, 9 Jun 2014 12:35:26 -0700 Subject: [PATCH 40/52] removed debug code --- .../src/octree/OctreeQueryNode.cpp | 20 +++++++++ .../src/octree/OctreeQueryNode.h | 11 ++--- .../src/octree/OctreeSendThread.cpp | 22 +++------- .../src/octree/OctreeSendThread.h | 2 +- assignment-client/src/octree/OctreeServer.cpp | 36 ++++------------ .../src/octree/SentPacketHistory.cpp | 5 ++- .../src/octree/SentPacketHistory.h | 1 - interface/src/Application.cpp | 42 ++++--------------- interface/src/Application.h | 4 +- libraries/networking/src/LimitedNodeList.cpp | 17 -------- libraries/networking/src/LimitedNodeList.h | 3 -- libraries/networking/src/PacketHeaders.h | 2 +- libraries/octree/src/OctreeSceneStats.cpp | 12 +++--- libraries/octree/src/OctreeSceneStats.h | 9 ++-- 14 files changed, 64 insertions(+), 122 deletions(-) diff --git a/assignment-client/src/octree/OctreeQueryNode.cpp b/assignment-client/src/octree/OctreeQueryNode.cpp index 5cfe5501e1..f8b5e34472 100644 --- a/assignment-client/src/octree/OctreeQueryNode.cpp +++ b/assignment-client/src/octree/OctreeQueryNode.cpp @@ -388,3 +388,23 @@ const QByteArray* OctreeQueryNode::getNextNackedPacket() { } return NULL; } + +void OctreeQueryNode::parseNackPacket(QByteArray& packet) { + + int numBytesPacketHeader = numBytesForPacketHeader(packet); + const unsigned char* dataAt = reinterpret_cast(packet.data()) + numBytesPacketHeader; + + uint16_t numSequenceNumbers = (*(uint16_t*)dataAt); + dataAt += sizeof(uint16_t); + + printf("\t received nack packet containing %d seq nums\n", numSequenceNumbers); + + // read sequence numbers + for (int i = 0; i < numSequenceNumbers; i++) { + OCTREE_PACKET_SEQUENCE sequenceNumber = (*(OCTREE_PACKET_SEQUENCE*)dataAt); + _nackedSequenceNumbers.enqueue(sequenceNumber); + dataAt += sizeof(OCTREE_PACKET_SEQUENCE); + + printf("\t seq = %d\n", sequenceNumber); + } +} diff --git a/assignment-client/src/octree/OctreeQueryNode.h b/assignment-client/src/octree/OctreeQueryNode.h index b79367503c..d955d3fdf7 100644 --- a/assignment-client/src/octree/OctreeQueryNode.h +++ b/assignment-client/src/octree/OctreeQueryNode.h @@ -24,8 +24,7 @@ #include #include // for SharedAssignmentPointer #include "SentPacketHistory.h" - -#include // i added dis +#include class OctreeSendThread; @@ -109,9 +108,7 @@ public: OCTREE_PACKET_SEQUENCE getSequenceNumber() const { return _sequenceNumber; } - void addNackedSequenceNumber(OCTREE_PACKET_SEQUENCE sequenceNumber) { - _nackedSequenceNumbers.append(sequenceNumber); - } + void parseNackPacket(QByteArray& packet); bool hasNextNackedPacket() const; const QByteArray* getNextNackedPacket(); @@ -158,8 +155,8 @@ private: PacketType _myPacketType; bool _isShuttingDown; -SentPacketHistory _sentPacketHistory; -QQueue _nackedSequenceNumbers; + SentPacketHistory _sentPacketHistory; + QQueue _nackedSequenceNumbers; }; #endif // hifi_OctreeQueryNode_h diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index 6f39cd28dc..30e3011ae8 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -85,7 +85,7 @@ bool OctreeSendThread::process() { if (nodeData && !nodeData->isShuttingDown()) { bool viewFrustumChanged = nodeData->updateCurrentViewFrustum(); packetDistributor(nodeData, viewFrustumChanged); -resendNackedPackets(nodeData); + resendNackedPackets(nodeData); } } } @@ -181,7 +181,7 @@ int OctreeSendThread::handlePacketSend(OctreeQueryNode* nodeData, int& trueBytes // actually send it OctreeServer::didCallWriteDatagram(this); -NodeList::getInstance()->writeDatagram2(nodeData->getSequenceNumber(), (char*) statsMessage, statsMessageLength, _node); + NodeList::getInstance()->writeDatagram((char*) statsMessage, statsMessageLength, _node); packetSent = true; } else { // not enough room in the packet, send two packets @@ -215,7 +215,7 @@ NodeList::getInstance()->writeDatagram2(nodeData->getSequenceNumber(), (char*) s packetsSent++; OctreeServer::didCallWriteDatagram(this); -NodeList::getInstance()->writeDatagram2(nodeData->getSequenceNumber(), (char*)nodeData->getPacket(), nodeData->getPacketLength(), _node); + NodeList::getInstance()->writeDatagram((char*)nodeData->getPacket(), nodeData->getPacketLength(), _node); packetSent = true; thisWastedBytes = MAX_PACKET_SIZE - nodeData->getPacketLength(); @@ -244,7 +244,7 @@ NodeList::getInstance()->writeDatagram2(nodeData->getSequenceNumber(), (char*)no if (nodeData->isPacketWaiting() && !nodeData->isShuttingDown()) { // just send the voxel packet OctreeServer::didCallWriteDatagram(this); -NodeList::getInstance()->writeDatagram2(nodeData->getSequenceNumber(), (char*)nodeData->getPacket(), nodeData->getPacketLength(), _node); + NodeList::getInstance()->writeDatagram((char*)nodeData->getPacket(), nodeData->getPacketLength(), _node); packetSent = true; int thisWastedBytes = MAX_PACKET_SIZE - nodeData->getPacketLength(); @@ -281,10 +281,6 @@ NodeList::getInstance()->writeDatagram2(nodeData->getSequenceNumber(), (char*)no return packetsSent; } - - - - int OctreeSendThread::resendNackedPackets(OctreeQueryNode* nodeData) { const int MAX_PACKETS_RESEND = 10; @@ -299,20 +295,12 @@ int OctreeSendThread::resendNackedPackets(OctreeQueryNode* nodeData) { _totalBytes += packet->size(); _totalPackets++; - _totalWastedBytes += MAX_PACKET_SIZE - packet->size(); // ??? + _totalWastedBytes += MAX_PACKET_SIZE - packet->size(); } } - -if (packetsSent > 0) -printf("\t\t re-sent %d packets!\n", packetsSent); return packetsSent; } - - - - - /// Version of voxel distributor that sends the deepest LOD level at once int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrustumChanged) { diff --git a/assignment-client/src/octree/OctreeSendThread.h b/assignment-client/src/octree/OctreeSendThread.h index cc0cdac3ad..e7599ebcd2 100644 --- a/assignment-client/src/octree/OctreeSendThread.h +++ b/assignment-client/src/octree/OctreeSendThread.h @@ -56,7 +56,7 @@ private: int _nodeMissingCount; bool _isShuttingDown; -int resendNackedPackets(OctreeQueryNode* nodeData); + int resendNackedPackets(OctreeQueryNode* nodeData); }; diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index 8cf1649cdb..9d3402b895 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -849,33 +849,15 @@ void OctreeServer::readPendingDatagrams() { } } else if (packetType == PacketTypeOctreeDataNack) { - -// parse packet for sequence numbers that need to be resent - -if (matchingNode) { - - OctreeQueryNode* nodeData = (OctreeQueryNode*)matchingNode->getLinkedData(); - - int numBytesPacketHeader = numBytesForPacketHeader(receivedPacket); - const unsigned char* dataAt = reinterpret_cast(receivedPacket.data()) + numBytesPacketHeader; - - uint16_t numSequenceNumbers = (*(uint16_t*)dataAt); - dataAt += sizeof(uint16_t); - -printf("\t received nack packet containing %d seq nums\n", numSequenceNumbers); - - // read sequence numbers - for (int i = 0; i < numSequenceNumbers; i++) { - OCTREE_PACKET_SEQUENCE sequenceNumber = (*(OCTREE_PACKET_SEQUENCE*)dataAt); - nodeData->addNackedSequenceNumber(sequenceNumber); - dataAt += sizeof(OCTREE_PACKET_SEQUENCE); - -printf("\t seq = %d\n", sequenceNumber); - } -} - - - + // 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); + } + } } else if (packetType == PacketTypeJurisdictionRequest) { _jurisdictionSender->queueReceivedPacket(matchingNode, receivedPacket); } else if (_octreeInboundPacketProcessor && getOctree()->handlesEditPacketType(packetType)) { diff --git a/assignment-client/src/octree/SentPacketHistory.cpp b/assignment-client/src/octree/SentPacketHistory.cpp index 0de163a23d..751e46e786 100644 --- a/assignment-client/src/octree/SentPacketHistory.cpp +++ b/assignment-client/src/octree/SentPacketHistory.cpp @@ -21,7 +21,8 @@ SentPacketHistory::SentPacketHistory(int size) void SentPacketHistory::packetSent(OCTREE_PACKET_SEQUENCE sequenceNumber, const QByteArray& packet) { _newestSequenceNumber = sequenceNumber; - // increment _newestPacketAt cyclically, insert new packet there + // increment _newestPacketAt cyclically, insert new packet there. + // this will overwrite the oldest packet in the buffer _newestPacketAt = (_newestPacketAt == _sentPackets.size() - 1) ? 0 : _newestPacketAt + 1; _sentPackets[_newestPacketAt] = packet; @@ -42,4 +43,4 @@ const QByteArray* SentPacketHistory::getPacket(OCTREE_PACKET_SEQUENCE sequenceNu if (packetAt < 0) { packetAt += _sentPackets.size(); } return &_sentPackets.at(packetAt); -} \ No newline at end of file +} diff --git a/assignment-client/src/octree/SentPacketHistory.h b/assignment-client/src/octree/SentPacketHistory.h index cbc50bc73c..4231400ac1 100644 --- a/assignment-client/src/octree/SentPacketHistory.h +++ b/assignment-client/src/octree/SentPacketHistory.h @@ -25,7 +25,6 @@ public: const QByteArray* getPacket(OCTREE_PACKET_SEQUENCE sequenceNumber) const; private: - QVector _sentPackets; // circular buffer int _newestPacketAt; int _numExistingPackets; diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 3ebfe728de..18a8d3ba12 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2095,33 +2095,17 @@ void Application::updateMyAvatar(float deltaTime) { } } -// sent a nack packet containing missing sequence numbers of received packets -{ - quint64 now = usecTimestampNow(); - quint64 sinceLastNack = now - _lastNackTime; - const quint64 TOO_LONG_SINCE_LAST_NACK = 250 * MSECS_PER_SECOND; - if (sinceLastNack > TOO_LONG_SINCE_LAST_NACK) { - _lastNackTime = now; - sendNack(); - } -} -} - -/*/ Attempt to identify the sender from it's address. - if (sendingNode) { - QUuid nodeUUID = sendingNode->getUUID(); - - // now that we know the node ID, let's add these stats to the stats for that node... - _octreeSceneStatsLock.lockForWrite(); - if (_octreeServerSceneStats.find(nodeUUID) != _octreeServerSceneStats.end()) { - OctreeSceneStats& stats = _octreeServerSceneStats[nodeUUID]; - stats.trackIncomingOctreePacket(packet, wasStatsPacket, sendingNode->getClockSkewUsec()); + // sent a nack packet containing missing sequence numbers of received packets + { + quint64 now = usecTimestampNow(); + quint64 sinceLastNack = now - _lastNackTime; + const quint64 TOO_LONG_SINCE_LAST_NACK = 250 * MSECS_PER_SECOND; + if (sinceLastNack > TOO_LONG_SINCE_LAST_NACK) { + _lastNackTime = now; + sendNack(); } - _octreeSceneStatsLock.unlock(); } - */ - - +} void Application::sendNack() { @@ -2139,7 +2123,6 @@ void Application::sendNack() { QUuid nodeUUID = node->getUUID(); - _octreeSceneStatsLock.lockForWrite(); // retreive octree scene stats of this node @@ -2172,15 +2155,11 @@ void Application::sendNack() { dataAt += sizeof(uint16_t); // pack sequence numbers -//printf("\n\t sending nack...\n"); -//printf("\t\t packed %d seq #s:", numSequenceNumbers); for (int i = 0; i < numSequenceNumbers; i++) { OCTREE_PACKET_SEQUENCE* sequenceNumberAt = (OCTREE_PACKET_SEQUENCE*)dataAt; *sequenceNumberAt = stats.getNextSequenceNumberToNack(); dataAt += sizeof(OCTREE_PACKET_SEQUENCE); -//printf(" %d,", *sequenceNumberAt); } -//printf("\n"); _octreeSceneStatsLock.unlock(); @@ -2189,9 +2168,6 @@ void Application::sendNack() { } } - - - void Application::queryOctree(NodeType_t serverType, PacketType packetType, NodeToJurisdictionMap& jurisdictions) { // if voxels are disabled, then don't send this at all... diff --git a/interface/src/Application.h b/interface/src/Application.h index 670ec35238..170be43493 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -413,8 +413,6 @@ private: void sendNack(); - - MainWindow* _window; GLCanvas* _glWidget; // our GLCanvas has a couple extra features @@ -585,7 +583,7 @@ private: QSystemTrayIcon* _trayIcon; -quint64 _lastNackTime; + quint64 _lastNackTime; }; #endif // hifi_Application_h diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index 15cebc26ac..c0d7941edf 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -271,23 +271,6 @@ qint64 LimitedNodeList::writeDatagram(const char* data, qint64 size, const Share return writeDatagram(QByteArray(data, size), destinationNode, overridenSockAddr); } -qint64 LimitedNodeList::writeDatagram2(int seq, const char* data, qint64 size, const SharedNodePointer& destinationNode, - const HifiSockAddr& overridenSockAddr) { - - qint64 ret = -1; - - if (randFloat() < 0.8f) { - ret = writeDatagram(QByteArray(data, size), destinationNode, overridenSockAddr); - } - else { - printf("dropped packet seq = %d --------------------------\n", seq); - } - - - return ret; -} - - qint64 LimitedNodeList::writeUnverifiedDatagram(const char* data, qint64 size, const SharedNodePointer& destinationNode, const HifiSockAddr& overridenSockAddr) { return writeUnverifiedDatagram(QByteArray(data, size), destinationNode, overridenSockAddr); diff --git a/libraries/networking/src/LimitedNodeList.h b/libraries/networking/src/LimitedNodeList.h index b3481885c8..a4bc8022bf 100644 --- a/libraries/networking/src/LimitedNodeList.h +++ b/libraries/networking/src/LimitedNodeList.h @@ -72,9 +72,6 @@ public: qint64 writeDatagram(const char* data, qint64 size, const SharedNodePointer& destinationNode, const HifiSockAddr& overridenSockAddr = HifiSockAddr()); -qint64 writeDatagram2(int seq, const char* data, qint64 size, const SharedNodePointer& destinationNode, - const HifiSockAddr& overridenSockAddr = HifiSockAddr()); - qint64 writeUnverifiedDatagram(const char* data, qint64 size, const SharedNodePointer& destinationNode, const HifiSockAddr& overridenSockAddr = HifiSockAddr()); diff --git a/libraries/networking/src/PacketHeaders.h b/libraries/networking/src/PacketHeaders.h index eac2f88870..8ac5333d10 100644 --- a/libraries/networking/src/PacketHeaders.h +++ b/libraries/networking/src/PacketHeaders.h @@ -76,7 +76,7 @@ const QSet NON_VERIFIED_PACKETS = QSet() << PacketTypeDomainList << PacketTypeDomainListRequest << PacketTypeDomainOAuthRequest << PacketTypeCreateAssignment << PacketTypeRequestAssignment << PacketTypeStunResponse << PacketTypeNodeJsonStats << PacketTypeVoxelQuery << PacketTypeParticleQuery << PacketTypeModelQuery -<< PacketTypeOctreeDataNack; + << PacketTypeOctreeDataNack; const int NUM_BYTES_MD5_HASH = 16; const int NUM_STATIC_HEADER_BYTES = sizeof(PacketVersion) + NUM_BYTES_RFC4122_UUID; diff --git a/libraries/octree/src/OctreeSceneStats.cpp b/libraries/octree/src/OctreeSceneStats.cpp index a93b2d0374..868ef29886 100644 --- a/libraries/octree/src/OctreeSceneStats.cpp +++ b/libraries/octree/src/OctreeSceneStats.cpp @@ -46,7 +46,7 @@ OctreeSceneStats::OctreeSceneStats() : _incomingReallyLate(0), _incomingPossibleDuplicate(0), _missingSequenceNumbers(), -_sequenceNumbersToNack(), + _sequenceNumbersToNack(), _incomingFlightTimeAverage(samples), _jurisdictionRoot(NULL) { @@ -159,7 +159,7 @@ void OctreeSceneStats::copyFromOther(const OctreeSceneStats& other) { _incomingPossibleDuplicate = other._incomingPossibleDuplicate; _missingSequenceNumbers = other._missingSequenceNumbers; -_sequenceNumbersToNack = other._sequenceNumbersToNack; + _sequenceNumbersToNack = other._sequenceNumbersToNack; } @@ -928,7 +928,7 @@ void OctreeSceneStats::trackIncomingOctreePacket(const QByteArray& packet, qDebug() << "found it in _missingSequenceNumbers"; } _missingSequenceNumbers.remove(sequence); -_sequenceNumbersToNack.remove(sequence); + _sequenceNumbersToNack.remove(sequence); _incomingLikelyLost--; _incomingRecovered++; } else { @@ -958,7 +958,7 @@ _sequenceNumbersToNack.remove(sequence); _incomingLikelyLost += missing; for(unsigned int missingSequence = expected; missingSequence < sequence; missingSequence++) { _missingSequenceNumbers << missingSequence; -_sequenceNumbersToNack << missingSequence; + _sequenceNumbersToNack << missingSequence; } } } @@ -986,7 +986,7 @@ _sequenceNumbersToNack << missingSequence; qDebug() << "pruning really old missing sequence:" << missingItem; } _missingSequenceNumbers.remove(missingItem); -_sequenceNumbersToNack.remove(missingItem); + _sequenceNumbersToNack.remove(missingItem); } } } @@ -1002,4 +1002,4 @@ uint16_t OctreeSceneStats::getNextSequenceNumberToNack() { uint16_t sequenceNumber = *it; _sequenceNumbersToNack.remove(sequenceNumber); return sequenceNumber; -} \ No newline at end of file +} diff --git a/libraries/octree/src/OctreeSceneStats.h b/libraries/octree/src/OctreeSceneStats.h index ca9bf7c74b..182bd6c86c 100644 --- a/libraries/octree/src/OctreeSceneStats.h +++ b/libraries/octree/src/OctreeSceneStats.h @@ -16,6 +16,7 @@ #include #include #include "JurisdictionMap.h" +#include "OctreePacketData.h" #define GREENISH 0x40ff40d0 #define YELLOWISH 0xffef40c0 @@ -172,8 +173,8 @@ public: quint32 getIncomingPossibleDuplicate() const { return _incomingPossibleDuplicate; } float getIncomingFlightTimeAverage() { return _incomingFlightTimeAverage.getAverage(); } -int getNumSequenceNumbersToNack() const; -uint16_t getNextSequenceNumberToNack(); + int getNumSequenceNumbersToNack() const; + OCTREE_PACKET_SEQUENCE getNextSequenceNumberToNack(); private: @@ -275,8 +276,8 @@ private: quint32 _incomingLate; /// out of order later than expected quint32 _incomingReallyLate; /// out of order and later than MAX_MISSING_SEQUENCE_OLD_AGE late quint32 _incomingPossibleDuplicate; /// out of order possibly a duplicate - QSet _missingSequenceNumbers; -QSet _sequenceNumbersToNack; + QSet _missingSequenceNumbers; + QSet _sequenceNumbersToNack; SimpleMovingAverage _incomingFlightTimeAverage; // features related items From 968ea3563caebf1ca080c62542ce32927135e98d Mon Sep 17 00:00:00 2001 From: wangyix Date: Mon, 9 Jun 2014 12:37:42 -0700 Subject: [PATCH 41/52] removed an extra space --- assignment-client/src/octree/OctreeServer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index 9d3402b895..f51d65fcef 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -834,11 +834,11 @@ void OctreeServer::readPendingDatagrams() { if (packetType == getMyQueryMessageType()) { // If we got a query packet, then we're talking to an agent, and we // need to make sure we have it in our nodeList. - if (matchingNode) { + if (matchingNode) { nodeList->updateNodeWithDataFromPacket(matchingNode, receivedPacket); OctreeQueryNode* nodeData = (OctreeQueryNode*)matchingNode->getLinkedData(); if (nodeData && !nodeData->isOctreeSendThreadInitalized()) { - + // NOTE: this is an important aspect of the proper ref counting. The send threads/node data need to // know that the OctreeServer/Assignment will not get deleted on it while it's still active. The // solution is to get the shared pointer for the current assignment. We need to make sure this is the From 0fce7e721a5135b742b71bd418519743ca799cc5 Mon Sep 17 00:00:00 2001 From: wangyix Date: Mon, 9 Jun 2014 12:40:01 -0700 Subject: [PATCH 42/52] removed more spaces --- assignment-client/src/octree/SentPacketHistory.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/assignment-client/src/octree/SentPacketHistory.cpp b/assignment-client/src/octree/SentPacketHistory.cpp index 751e46e786..85e164bc41 100644 --- a/assignment-client/src/octree/SentPacketHistory.cpp +++ b/assignment-client/src/octree/SentPacketHistory.cpp @@ -20,12 +20,11 @@ SentPacketHistory::SentPacketHistory(int size) void SentPacketHistory::packetSent(OCTREE_PACKET_SEQUENCE sequenceNumber, const QByteArray& packet) { _newestSequenceNumber = sequenceNumber; - + // increment _newestPacketAt cyclically, insert new packet there. // this will overwrite the oldest packet in the buffer _newestPacketAt = (_newestPacketAt == _sentPackets.size() - 1) ? 0 : _newestPacketAt + 1; _sentPackets[_newestPacketAt] = packet; - if (_numExistingPackets < _sentPackets.size()) { _numExistingPackets++; } @@ -33,14 +32,11 @@ void SentPacketHistory::packetSent(OCTREE_PACKET_SEQUENCE sequenceNumber, const const QByteArray* SentPacketHistory::getPacket(OCTREE_PACKET_SEQUENCE sequenceNumber) const { - OCTREE_PACKET_SEQUENCE seqDiff = _newestSequenceNumber - sequenceNumber; if (!(seqDiff >= 0 && seqDiff < _numExistingPackets)) { return NULL; } - int packetAt = _newestPacketAt - seqDiff; if (packetAt < 0) { packetAt += _sentPackets.size(); } - return &_sentPackets.at(packetAt); } From 412d3e19fecab6dec650ae7842beddf5b282fc50 Mon Sep 17 00:00:00 2001 From: wangyix Date: Mon, 9 Jun 2014 12:56:00 -0700 Subject: [PATCH 43/52] removed debug prints in parseNackPacket() --- assignment-client/src/octree/OctreeQueryNode.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/assignment-client/src/octree/OctreeQueryNode.cpp b/assignment-client/src/octree/OctreeQueryNode.cpp index f8b5e34472..372f15a76b 100644 --- a/assignment-client/src/octree/OctreeQueryNode.cpp +++ b/assignment-client/src/octree/OctreeQueryNode.cpp @@ -394,17 +394,14 @@ void OctreeQueryNode::parseNackPacket(QByteArray& packet) { int numBytesPacketHeader = numBytesForPacketHeader(packet); const unsigned char* dataAt = reinterpret_cast(packet.data()) + numBytesPacketHeader; + // read number of sequence numbers uint16_t numSequenceNumbers = (*(uint16_t*)dataAt); dataAt += sizeof(uint16_t); - printf("\t received nack packet containing %d seq nums\n", numSequenceNumbers); - // read sequence numbers for (int i = 0; i < numSequenceNumbers; i++) { OCTREE_PACKET_SEQUENCE sequenceNumber = (*(OCTREE_PACKET_SEQUENCE*)dataAt); _nackedSequenceNumbers.enqueue(sequenceNumber); dataAt += sizeof(OCTREE_PACKET_SEQUENCE); - - printf("\t seq = %d\n", sequenceNumber); } } From ff2a5342ee8f4208b465fabc2c925954b225e90b Mon Sep 17 00:00:00 2001 From: wangyix Date: Mon, 9 Jun 2014 12:57:50 -0700 Subject: [PATCH 44/52] removed another extra space --- assignment-client/src/octree/OctreeServer.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index f51d65fcef..cb60f0816e 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -847,7 +847,6 @@ void OctreeServer::readPendingDatagrams() { nodeData->initializeOctreeSendThread(sharedAssignment, matchingNode); } } - } else if (packetType == PacketTypeOctreeDataNack) { // 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. From e45f2fed4b83b9014c5cfeb20c810fe04dde0239 Mon Sep 17 00:00:00 2001 From: wangyix Date: Mon, 9 Jun 2014 13:42:45 -0700 Subject: [PATCH 45/52] changed writelock to readlock plus a coding standard fix --- assignment-client/src/octree/SentPacketHistory.cpp | 4 +++- interface/src/Application.cpp | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/assignment-client/src/octree/SentPacketHistory.cpp b/assignment-client/src/octree/SentPacketHistory.cpp index 85e164bc41..0ea7fd8b69 100644 --- a/assignment-client/src/octree/SentPacketHistory.cpp +++ b/assignment-client/src/octree/SentPacketHistory.cpp @@ -37,6 +37,8 @@ const QByteArray* SentPacketHistory::getPacket(OCTREE_PACKET_SEQUENCE sequenceNu return NULL; } int packetAt = _newestPacketAt - seqDiff; - if (packetAt < 0) { packetAt += _sentPackets.size(); } + if (packetAt < 0) { + packetAt += _sentPackets.size(); + } return &_sentPackets.at(packetAt); } diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 18a8d3ba12..574df09ee2 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2123,7 +2123,7 @@ void Application::sendNack() { QUuid nodeUUID = node->getUUID(); - _octreeSceneStatsLock.lockForWrite(); + _octreeSceneStatsLock.lockForRead(); // retreive octree scene stats of this node if (_octreeServerSceneStats.find(nodeUUID) == _octreeServerSceneStats.end()) { From ee71d34f021ba90327ac96e1b9094c858679604f Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 9 Jun 2014 14:03:47 -0700 Subject: [PATCH 46/52] add a crash guard around negative silent samples --- libraries/audio/src/PositionalAudioRingBuffer.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libraries/audio/src/PositionalAudioRingBuffer.cpp b/libraries/audio/src/PositionalAudioRingBuffer.cpp index 94a88897e3..bb47c6de9e 100644 --- a/libraries/audio/src/PositionalAudioRingBuffer.cpp +++ b/libraries/audio/src/PositionalAudioRingBuffer.cpp @@ -55,7 +55,9 @@ int PositionalAudioRingBuffer::parseData(const QByteArray& packet) { readBytes += sizeof(int16_t); - addSilentFrame(numSilentSamples); + if (numSilentSamples > 0) { + addSilentFrame(numSilentSamples); + } } else { // there is audio data to read readBytes += writeData(packet.data() + readBytes, packet.size() - readBytes); From 8312e1642db0a0178997cb096684b14eb030aec9 Mon Sep 17 00:00:00 2001 From: wangyix Date: Mon, 9 Jun 2014 15:15:43 -0700 Subject: [PATCH 47/52] replaced takeFirst() with dequeue() for consistency --- assignment-client/src/octree/OctreeQueryNode.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assignment-client/src/octree/OctreeQueryNode.cpp b/assignment-client/src/octree/OctreeQueryNode.cpp index 372f15a76b..3531c3f9cb 100644 --- a/assignment-client/src/octree/OctreeQueryNode.cpp +++ b/assignment-client/src/octree/OctreeQueryNode.cpp @@ -384,7 +384,7 @@ bool OctreeQueryNode::hasNextNackedPacket() const { const QByteArray* OctreeQueryNode::getNextNackedPacket() { if (!_nackedSequenceNumbers.isEmpty()) { // could return null if packet is not in the history - return _sentPacketHistory.getPacket(_nackedSequenceNumbers.takeFirst()); + return _sentPacketHistory.getPacket(_nackedSequenceNumbers.dequeue()); } return NULL; } From e8b6338de9026938a34ac35191a4abb1d906ecc6 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 9 Jun 2014 15:40:29 -0700 Subject: [PATCH 48/52] Fix IK for hydra hands. --- interface/src/avatar/SkeletonModel.cpp | 45 +++++++++----------------- interface/src/renderer/Model.cpp | 4 +-- 2 files changed, 17 insertions(+), 32 deletions(-) diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index ca40ba1d64..d5a13b0381 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -144,9 +144,9 @@ void SkeletonModel::getBodyShapes(QVector& shapes) const { void SkeletonModel::renderIKConstraints() { renderJointConstraints(getRightHandJointIndex()); renderJointConstraints(getLeftHandJointIndex()); - if (isActive() && _owningAvatar->isMyAvatar()) { - renderRagDoll(); - } + //if (isActive() && _owningAvatar->isMyAvatar()) { + // renderRagDoll(); + //} } class IndexValue { @@ -193,45 +193,30 @@ void SkeletonModel::applyPalmData(int jointIndex, PalmData& palm) { if (parentJointIndex == -1) { return; } - + // rotate palm to align with its normal (normal points out of hand's palm) - glm::quat palmRotation; - glm::quat r0, r1; - if (!Menu::getInstance()->isOptionChecked(MenuOption::AlternateIK) && - Menu::getInstance()->isOptionChecked(MenuOption::AlignForearmsWithWrists)) { - JointState parentState = _jointStates[parentJointIndex]; - palmRotation = parentState.getRotationFromBindToModelFrame(); - r0 = palmRotation; - } else { - JointState state = _jointStates[jointIndex]; - palmRotation = state.getRotationFromBindToModelFrame(); - } glm::quat inverseRotation = glm::inverse(_rotation); - glm::vec3 palmNormal = inverseRotation * palm.getNormal(); - palmRotation = rotationBetween(palmRotation * geometry.palmDirection, palmNormal) * palmRotation; - r1 = palmRotation; - - // rotate palm to align with finger direction - glm::vec3 direction = inverseRotation * palm.getFingerDirection(); - palmRotation = rotationBetween(palmRotation * glm::vec3(-sign, 0.0f, 0.0f), direction) * palmRotation; - - // set hand position, rotation glm::vec3 palmPosition = inverseRotation * (palm.getPosition() - _translation); + glm::vec3 palmNormal = inverseRotation * palm.getNormal(); + glm::vec3 fingerDirection = inverseRotation * palm.getFingerDirection(); + + glm::quat palmRotation = rotationBetween(glm::vec3(0.0f, -1.0f, 0.0f), palmNormal); + palmRotation = rotationBetween(palmRotation * glm::vec3(-sign, 0.0f, 0.0f), fingerDirection) * palmRotation; + if (Menu::getInstance()->isOptionChecked(MenuOption::AlternateIK)) { setHandPosition(jointIndex, palmPosition, palmRotation); - } else if (Menu::getInstance()->isOptionChecked(MenuOption::AlignForearmsWithWrists)) { - glm::vec3 forearmVector = palmRotation * glm::vec3(sign, 0.0f, 0.0f); - setJointPosition(parentJointIndex, palmPosition + forearmVector * - geometry.joints.at(jointIndex).distanceToParent * extractUniformScale(_scale), + float forearmLength = geometry.joints.at(jointIndex).distanceToParent * extractUniformScale(_scale); + glm::vec3 forearm = palmRotation * glm::vec3(sign * forearmLength, 0.0f, 0.0f); + setJointPosition(parentJointIndex, palmPosition + forearm, glm::quat(), false, -1, false, glm::vec3(0.0f, -1.0f, 0.0f), PALM_PRIORITY); JointState& parentState = _jointStates[parentJointIndex]; parentState.setRotationFromBindFrame(palmRotation, PALM_PRIORITY); // lock hand to forearm by slamming its rotation (in parent-frame) to identity _jointStates[jointIndex]._rotationInParentFrame = glm::quat(); } else { - setJointPosition(jointIndex, palmPosition, palmRotation, - true, -1, false, glm::vec3(0.0f, -1.0f, 0.0f), PALM_PRIORITY); + setJointPosition(jointIndex, palmPosition, palmRotation, + true, -1, false, glm::vec3(0.0f, -1.0f, 0.0f), PALM_PRIORITY); } } diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 105301054b..aff023c2a0 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -1275,8 +1275,8 @@ bool Model::setJointPosition(int jointIndex, const glm::vec3& position, const gl if (useRotation) { JointState& state = _jointStates[jointIndex]; - state.setRotation(rotation, true, priority); - endRotation = state.getRotation(); + state.setRotationFromBindFrame(rotation, priority); + endRotation = state.getRotationFromBindToModelFrame(); } // then, we go from the joint upwards, rotating the end as close as possible to the target From 589b2e8fb758d8af3872733a9e9a3fdd81a6976e Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 9 Jun 2014 16:12:54 -0700 Subject: [PATCH 49/52] recover some code for one less magic vec3 --- interface/src/avatar/SkeletonModel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index d5a13b0381..1b1b2e032b 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -200,7 +200,7 @@ void SkeletonModel::applyPalmData(int jointIndex, PalmData& palm) { glm::vec3 palmNormal = inverseRotation * palm.getNormal(); glm::vec3 fingerDirection = inverseRotation * palm.getFingerDirection(); - glm::quat palmRotation = rotationBetween(glm::vec3(0.0f, -1.0f, 0.0f), palmNormal); + glm::quat palmRotation = rotationBetween(geometry.palmDirection, palmNormal); palmRotation = rotationBetween(palmRotation * glm::vec3(-sign, 0.0f, 0.0f), fingerDirection) * palmRotation; if (Menu::getInstance()->isOptionChecked(MenuOption::AlternateIK)) { From de61029f05923fb32f700037b2c815db51008431 Mon Sep 17 00:00:00 2001 From: wangyix Date: Mon, 9 Jun 2014 17:30:09 -0700 Subject: [PATCH 50/52] Added dev menu option to disable nack packets --- interface/src/Application.cpp | 6 +++++- interface/src/Menu.cpp | 2 ++ interface/src/Menu.h | 1 + 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 574df09ee2..22fe5887fd 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2099,7 +2099,7 @@ void Application::updateMyAvatar(float deltaTime) { { quint64 now = usecTimestampNow(); quint64 sinceLastNack = now - _lastNackTime; - const quint64 TOO_LONG_SINCE_LAST_NACK = 250 * MSECS_PER_SECOND; + const quint64 TOO_LONG_SINCE_LAST_NACK = 1 * USECS_PER_SECOND; if (sinceLastNack > TOO_LONG_SINCE_LAST_NACK) { _lastNackTime = now; sendNack(); @@ -2109,6 +2109,10 @@ void Application::updateMyAvatar(float deltaTime) { void Application::sendNack() { + if (Menu::getInstance()->isOptionChecked(MenuOption::NackDisable)) { + return; + } + char packet[MAX_PACKET_SIZE]; NodeList* nodeList = NodeList::getInstance(); diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 9ab47cdeda..9381790a42 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -393,6 +393,8 @@ Menu::Menu() : addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::AlignForearmsWithWrists, 0, true); addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::AlternateIK, 0, false); + addCheckableActionToQMenuAndActionHash(developerMenu, MenuOption::NackDisable, 0, false); + addDisabledActionAndSeparator(developerMenu, "Testing"); QMenu* timingMenu = developerMenu->addMenu("Timing and Statistics Tools"); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index f9af80119b..e1bbb382aa 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -373,6 +373,7 @@ namespace MenuOption { const QString MoveWithLean = "Move with Lean"; const QString MuteAudio = "Mute Microphone"; const QString MuteEnvironment = "Mute Environment"; + const QString NackDisable = "Disable NACK Packets"; const QString NameLocation = "Name this location"; const QString NewVoxelCullingMode = "New Voxel Culling Mode"; const QString OctreeStats = "Voxel and Particle Statistics"; From 4665df4d1fd9f314a1c743a92abb5efb7419cffb Mon Sep 17 00:00:00 2001 From: wangyix Date: Mon, 9 Jun 2014 17:41:20 -0700 Subject: [PATCH 51/52] nackdisable to disablenack --- interface/src/Application.cpp | 2 +- interface/src/Menu.cpp | 2 +- interface/src/Menu.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 22fe5887fd..3ed2d84df7 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2109,7 +2109,7 @@ void Application::updateMyAvatar(float deltaTime) { void Application::sendNack() { - if (Menu::getInstance()->isOptionChecked(MenuOption::NackDisable)) { + if (Menu::getInstance()->isOptionChecked(MenuOption::DisableNack)) { return; } diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 9381790a42..be5dd13d1c 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -393,7 +393,7 @@ Menu::Menu() : addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::AlignForearmsWithWrists, 0, true); addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::AlternateIK, 0, false); - addCheckableActionToQMenuAndActionHash(developerMenu, MenuOption::NackDisable, 0, false); + addCheckableActionToQMenuAndActionHash(developerMenu, MenuOption::DisableNack, 0, false); addDisabledActionAndSeparator(developerMenu, "Testing"); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index e1bbb382aa..19e7ef98e2 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -320,6 +320,7 @@ namespace MenuOption { const QString DecreaseAvatarSize = "Decrease Avatar Size"; const QString DecreaseVoxelSize = "Decrease Voxel Size"; const QString DisableAutoAdjustLOD = "Disable Automatically Adjusting LOD"; + const QString DisableNack = "Disable NACK Packets"; const QString DisplayFrustum = "Display Frustum"; const QString DisplayHands = "Display Hands"; const QString DisplayHandTargets = "Display Hand Targets"; @@ -373,7 +374,6 @@ namespace MenuOption { const QString MoveWithLean = "Move with Lean"; const QString MuteAudio = "Mute Microphone"; const QString MuteEnvironment = "Mute Environment"; - const QString NackDisable = "Disable NACK Packets"; const QString NameLocation = "Name this location"; const QString NewVoxelCullingMode = "New Voxel Culling Mode"; const QString OctreeStats = "Voxel and Particle Statistics"; From ffda98fe0b160083f7ab3bea64811f8271350a9f Mon Sep 17 00:00:00 2001 From: wangyix Date: Mon, 9 Jun 2014 17:50:29 -0700 Subject: [PATCH 52/52] var name change again --- interface/src/Application.cpp | 2 +- interface/src/Menu.cpp | 2 +- interface/src/Menu.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 3ed2d84df7..3cfec3190e 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2109,7 +2109,7 @@ void Application::updateMyAvatar(float deltaTime) { void Application::sendNack() { - if (Menu::getInstance()->isOptionChecked(MenuOption::DisableNack)) { + if (Menu::getInstance()->isOptionChecked(MenuOption::DisableNackPackets)) { return; } diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index be5dd13d1c..42874ea02e 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -393,7 +393,7 @@ Menu::Menu() : addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::AlignForearmsWithWrists, 0, true); addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::AlternateIK, 0, false); - addCheckableActionToQMenuAndActionHash(developerMenu, MenuOption::DisableNack, 0, false); + addCheckableActionToQMenuAndActionHash(developerMenu, MenuOption::DisableNackPackets, 0, false); addDisabledActionAndSeparator(developerMenu, "Testing"); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 19e7ef98e2..03ffa0b848 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -320,7 +320,7 @@ namespace MenuOption { const QString DecreaseAvatarSize = "Decrease Avatar Size"; const QString DecreaseVoxelSize = "Decrease Voxel Size"; const QString DisableAutoAdjustLOD = "Disable Automatically Adjusting LOD"; - const QString DisableNack = "Disable NACK Packets"; + const QString DisableNackPackets = "Disable NACK Packets"; const QString DisplayFrustum = "Display Frustum"; const QString DisplayHands = "Display Hands"; const QString DisplayHandTargets = "Display Hand Targets";