diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index ab4b20b9cc..5e0cd740e6 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -103,11 +103,6 @@ AudioMixer::AudioMixer(ReceivedMessage& message) : ); connect(nodeList.data(), &NodeList::nodeKilled, this, &AudioMixer::handleNodeKilled); - connect(nodeList.data(), &NodeList::nodeAdded, this, [this](const SharedNodePointer& node) { - if (node->getType() == NodeType::DownstreamAudioMixer) { - node->activatePublicSocket(); - } - }); } void AudioMixer::queueAudioPacket(QSharedPointer message, SharedNodePointer node) { @@ -389,7 +384,10 @@ void AudioMixer::start() { auto nodeList = DependencyManager::get(); // prepare the NodeList - nodeList->addSetOfNodeTypesToNodeInterestSet({ NodeType::Agent, NodeType::DownstreamAudioMixer, NodeType::EntityScriptServer }); + nodeList->addSetOfNodeTypesToNodeInterestSet({ + NodeType::Agent, NodeType::EntityScriptServer, + NodeType::UpstreamAudioMixer, NodeType::DownstreamAudioMixer + }); nodeList->linkedDataCreateCallback = [&](Node* node) { getOrCreateClientData(node); }; // parse out any AudioMixer settings diff --git a/assignment-client/src/audio/AudioMixer.h b/assignment-client/src/audio/AudioMixer.h index e542d82a6a..ed3a5b0541 100644 --- a/assignment-client/src/audio/AudioMixer.h +++ b/assignment-client/src/audio/AudioMixer.h @@ -51,6 +51,11 @@ public: static const QVector& getReverbSettings() { return _zoneReverbSettings; } static const std::pair negotiateCodec(std::vector codecs); + static bool shouldReplicateTo(const Node& from, const Node& to) { + return to.getType() == NodeType::DownstreamAudioMixer && + to.getPublicSocket() != from.getPublicSocket() && + to.getLocalSocket() != from.getLocalSocket(); + } public slots: void run() override; void sendStatsPacket() override; diff --git a/assignment-client/src/audio/AudioMixerClientData.cpp b/assignment-client/src/audio/AudioMixerClientData.cpp index bf19a02d9a..408ddf038c 100644 --- a/assignment-client/src/audio/AudioMixerClientData.cpp +++ b/assignment-client/src/audio/AudioMixerClientData.cpp @@ -67,24 +67,25 @@ void AudioMixerClientData::processPackets() { case PacketType::MicrophoneAudioNoEcho: case PacketType::MicrophoneAudioWithEcho: case PacketType::InjectAudio: - case PacketType::AudioStreamStats: - case PacketType::SilentAudioFrame: - case PacketType::ReplicatedMicrophoneAudioNoEcho: - case PacketType::ReplicatedMicrophoneAudioWithEcho: - case PacketType::ReplicatedInjectAudio: - case PacketType::ReplicatedSilentAudioFrame: { + case PacketType::SilentAudioFrame: { - if (node->isUpstream() && !_hasSetupCodecForUpstreamNode) { + if (node->isUpstream()) { setupCodecForReplicatedAgent(packet); } QMutexLocker lock(&getMutex()); parseData(*packet); - + optionallyReplicatePacket(*packet, *node); break; } + case PacketType::AudioStreamStats: { + QMutexLocker lock(&getMutex()); + parseData(*packet); + + break; + } case PacketType::NegotiateAudioFormat: negotiateAudioFormat(*packet, node); break; @@ -141,7 +142,7 @@ void AudioMixerClientData::optionallyReplicatePacket(ReceivedMessage& message, c // enumerate the downstream audio mixers and send them the replicated version of this packet nodeList->unsafeEachNode([&](const SharedNodePointer& downstreamNode) { - if (downstreamNode->getType() == NodeType::DownstreamAudioMixer) { + if (AudioMixer::shouldReplicateTo(node, *downstreamNode)) { // construct the packet only once, if we have any downstream audio mixers to send to if (!packet) { // construct an NLPacket to send to the replicant that has the contents of the received packet @@ -687,14 +688,14 @@ void AudioMixerClientData::setupCodecForReplicatedAgent(QSharedPointerreadString(); - qDebug() << "Manually setting codec for replicated agent" << uuidStringWithoutCurlyBraces(getNodeID()) + if (codecString != _selectedCodecName) { + qDebug() << "Manually setting codec for replicated agent" << uuidStringWithoutCurlyBraces(getNodeID()) << "-" << codecString; - const std::pair codec = AudioMixer::negotiateCodec({ codecString }); - setupCodec(codec.second, codec.first); + const std::pair codec = AudioMixer::negotiateCodec({ codecString }); + setupCodec(codec.second, codec.first); - _hasSetupCodecForUpstreamNode = true; - - // seek back to the beginning of the message so other readers are in the right place - message->seek(0); + // seek back to the beginning of the message so other readers are in the right place + message->seek(0); + } } diff --git a/assignment-client/src/audio/AudioMixerClientData.h b/assignment-client/src/audio/AudioMixerClientData.h index 76a9cd6aa7..7a8690d8cc 100644 --- a/assignment-client/src/audio/AudioMixerClientData.h +++ b/assignment-client/src/audio/AudioMixerClientData.h @@ -184,8 +184,6 @@ private: bool _shouldMuteClient { false }; bool _requestsDomainListData { false }; - - bool _hasSetupCodecForUpstreamNode { false }; }; #endif // hifi_AudioMixerClientData_h diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index f1e30f4442..3a5116a2e9 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -66,7 +66,6 @@ AvatarMixer::AvatarMixer(ReceivedMessage& message) : connect(nodeList.data(), &NodeList::nodeAdded, this, [this](const SharedNodePointer& node) { if (node->getType() == NodeType::DownstreamAvatarMixer) { getOrCreateClientData(node); - node->activatePublicSocket(); } }); } @@ -144,8 +143,8 @@ void AvatarMixer::optionallyReplicatePacket(ReceivedMessage& message, const Node std::unique_ptr packet; auto nodeList = DependencyManager::get(); - nodeList->eachMatchingNode([&](const SharedNodePointer& node) { - return node->getType() == NodeType::DownstreamAvatarMixer; + nodeList->eachMatchingNode([&](const SharedNodePointer& downstreamNode) { + return shouldReplicateTo(node, *downstreamNode); }, [&](const SharedNodePointer& node) { if (!packet) { // construct an NLPacket to send to the replicant that has the contents of the received packet @@ -165,10 +164,6 @@ void AvatarMixer::queueIncomingPacket(QSharedPointer message, S _queueIncomingPacketElapsedTime += (end - start); } - -AvatarMixer::~AvatarMixer() { -} - void AvatarMixer::sendIdentityPacket(AvatarMixerClientData* nodeData, const SharedNodePointer& destinationNode) { if (destinationNode->getType() == NodeType::Agent && !destinationNode->isUpstream()) { QByteArray individualData = nodeData->getAvatar().identityByteArray(); @@ -331,7 +326,13 @@ void AvatarMixer::manageIdentityData(const SharedNodePointer& node) { } } if (sendIdentity) { - sendIdentityPacket(nodeData, node); // Tell node whose name changed about its new session display name or avatar. + + // since this packet includes a change to either the skeleton model URL or the display name + // it needs a new sequence number + nodeData->getAvatar().pushIdentitySequenceNumber(); + + // tell node whose name changed about its new session display name or avatar. + sendIdentityPacket(nodeData, node); } } @@ -423,8 +424,8 @@ void AvatarMixer::nodeKilled(SharedNodePointer killedNode) { nodeList->eachMatchingNode([&](const SharedNodePointer& node) { // we relay avatar kill packets to agents that are not upstream // and downstream avatar mixers, if the node that was just killed was being replicated - return (node->getType() == NodeType::Agent && !node->isUpstream()) - || (killedNode->isReplicated() && node->getType() == NodeType::DownstreamAvatarMixer); + return (node->getType() == NodeType::Agent && !node->isUpstream()) || + (killedNode->isReplicated() && shouldReplicateTo(*killedNode, *node)); }, [&](const SharedNodePointer& node) { if (node->getType() == NodeType::Agent) { if (!killPacket) { @@ -856,7 +857,10 @@ AvatarMixerClientData* AvatarMixer::getOrCreateClientData(SharedNodePointer node void AvatarMixer::domainSettingsRequestComplete() { auto nodeList = DependencyManager::get(); - nodeList->addSetOfNodeTypesToNodeInterestSet({ NodeType::Agent, NodeType::DownstreamAvatarMixer, NodeType::EntityScriptServer }); + nodeList->addSetOfNodeTypesToNodeInterestSet({ + NodeType::Agent, NodeType::EntityScriptServer, + NodeType::UpstreamAvatarMixer, NodeType::DownstreamAvatarMixer + }); // parse the settings to pull out the values we need parseDomainServerSettings(nodeList->getDomainHandler().getSettingsObject()); diff --git a/assignment-client/src/avatars/AvatarMixer.h b/assignment-client/src/avatars/AvatarMixer.h index 58d4487652..610da8ad57 100644 --- a/assignment-client/src/avatars/AvatarMixer.h +++ b/assignment-client/src/avatars/AvatarMixer.h @@ -28,7 +28,13 @@ class AvatarMixer : public ThreadedAssignment { Q_OBJECT public: AvatarMixer(ReceivedMessage& message); - ~AvatarMixer(); + + static bool shouldReplicateTo(const Node& from, const Node& to) { + return to.getType() == NodeType::DownstreamAvatarMixer && + to.getPublicSocket() != from.getPublicSocket() && + to.getLocalSocket() != from.getLocalSocket(); + } + public slots: /// runs the avatar mixer void run() override; diff --git a/assignment-client/src/avatars/AvatarMixerSlave.cpp b/assignment-client/src/avatars/AvatarMixerSlave.cpp index 8092518454..bbf68f0e22 100644 --- a/assignment-client/src/avatars/AvatarMixerSlave.cpp +++ b/assignment-client/src/avatars/AvatarMixerSlave.cpp @@ -79,13 +79,13 @@ int AvatarMixerSlave::sendIdentityPacket(const AvatarMixerClientData* nodeData, } } -int AvatarMixerSlave::sendReplicatedIdentityPacket(const AvatarMixerClientData* nodeData, const SharedNodePointer& destinationNode) { - if (destinationNode->getType() == NodeType::DownstreamAvatarMixer) { +int AvatarMixerSlave::sendReplicatedIdentityPacket(const Node& agentNode, const AvatarMixerClientData* nodeData, const Node& destinationNode) { + if (AvatarMixer::shouldReplicateTo(agentNode, destinationNode)) { QByteArray individualData = nodeData->getConstAvatarData()->identityByteArray(); individualData.replace(0, NUM_BYTES_RFC4122_UUID, nodeData->getNodeID().toRfc4122()); // FIXME, this looks suspicious - auto identityPacket = NLPacket::create(PacketType::ReplicatedAvatarIdentity); + auto identityPacket = NLPacketList::create(PacketType::ReplicatedAvatarIdentity, QByteArray(), true, true); identityPacket->write(individualData); - DependencyManager::get()->sendUnreliablePacket(*identityPacket, *destinationNode); + DependencyManager::get()->sendPacketList(std::move(identityPacket), destinationNode); _stats.numIdentityPackets++; return individualData.size(); } else { @@ -453,6 +453,10 @@ void AvatarMixerSlave::broadcastAvatarDataToDownstreamMixer(const SharedNodePoin nodeData->resetNumAvatarsSentLastFrame(); std::for_each(_begin, _end, [&](const SharedNodePointer& agentNode) { + if (!AvatarMixer::shouldReplicateTo(*agentNode, *node)) { + return; + } + // collect agents that we have avatar data for that we are supposed to replicate if (agentNode->getType() == NodeType::Agent && agentNode->getLinkedData() && agentNode->isReplicated()) { const AvatarMixerClientData* agentNodeData = reinterpret_cast(agentNode->getLinkedData()); @@ -479,7 +483,7 @@ void AvatarMixerSlave::broadcastAvatarDataToDownstreamMixer(const SharedNodePoin auto lastBroadcastTime = nodeData->getLastBroadcastTime(agentNode->getUUID()); if (lastBroadcastTime <= agentNodeData->getIdentityChangeTimestamp() || (start - lastBroadcastTime) >= REBROADCAST_IDENTITY_TO_DOWNSTREAM_EVERY_US) { - sendReplicatedIdentityPacket(agentNodeData, node); + sendReplicatedIdentityPacket(*agentNode, agentNodeData, *node); nodeData->setLastBroadcastTime(agentNode->getUUID(), start); } diff --git a/assignment-client/src/avatars/AvatarMixerSlave.h b/assignment-client/src/avatars/AvatarMixerSlave.h index 69c707bbf1..bdddd5ceab 100644 --- a/assignment-client/src/avatars/AvatarMixerSlave.h +++ b/assignment-client/src/avatars/AvatarMixerSlave.h @@ -95,7 +95,7 @@ public: private: int sendIdentityPacket(const AvatarMixerClientData* nodeData, const SharedNodePointer& destinationNode); - int sendReplicatedIdentityPacket(const AvatarMixerClientData* nodeData, const SharedNodePointer& destinationNode); + int sendReplicatedIdentityPacket(const Node& agentNode, const AvatarMixerClientData* nodeData, const Node& destinationNode); void broadcastAvatarDataToAgent(const SharedNodePointer& node); void broadcastAvatarDataToDownstreamMixer(const SharedNodePointer& node); diff --git a/cmake/macros/SetupHifiLibrary.cmake b/cmake/macros/SetupHifiLibrary.cmake index e4a286cf3f..d0fc58af0c 100644 --- a/cmake/macros/SetupHifiLibrary.cmake +++ b/cmake/macros/SetupHifiLibrary.cmake @@ -35,6 +35,23 @@ macro(SETUP_HIFI_LIBRARY) endif() endforeach() + # add compiler flags to AVX512 source files, if supported by compiler + include(CheckCXXCompilerFlag) + file(GLOB_RECURSE AVX512_SRCS "src/avx512/*.cpp" "src/avx512/*.c") + foreach(SRC ${AVX512_SRCS}) + if (WIN32) + check_cxx_compiler_flag("/arch:AVX512" COMPILER_SUPPORTS_AVX512) + if (COMPILER_SUPPORTS_AVX512) + set_source_files_properties(${SRC} PROPERTIES COMPILE_FLAGS /arch:AVX512) + endif() + elseif (APPLE OR UNIX) + check_cxx_compiler_flag("-mavx512f" COMPILER_SUPPORTS_AVX512) + if (COMPILER_SUPPORTS_AVX512) + set_source_files_properties(${SRC} PROPERTIES COMPILE_FLAGS -mavx512f) + endif() + endif() + endforeach() + setup_memory_debugger() # create a library and set the property so it can be referenced later diff --git a/cmake/modules/FindFBX.cmake b/cmake/modules/FindFBX.cmake index 7f6a424aa1..2e84d1ea19 100644 --- a/cmake/modules/FindFBX.cmake +++ b/cmake/modules/FindFBX.cmake @@ -29,6 +29,7 @@ string(REGEX REPLACE "^[0-9]+\\.([0-9]+).*$" "\\1" FBX_VERSION_MINOR "${FBX_VER string(REGEX REPLACE "^[0-9]+\\.[0-9]+\\.([0-9]+).*$" "\\1" FBX_VERSION_PATCH "${FBX_VERSION}") set(FBX_MAC_LOCATIONS "/Applications/Autodesk/FBX\ SDK/${FBX_VERSION}") +set(FBX_LINUX_LOCATIONS "/usr/local/lib/gcc4/x64/debug/") if (WIN32) string(REGEX REPLACE "\\\\" "/" WIN_PROGRAM_FILES_X64_DIRECTORY $ENV{ProgramW6432}) @@ -36,7 +37,7 @@ endif() set(FBX_WIN_LOCATIONS "${WIN_PROGRAM_FILES_X64_DIRECTORY}/Autodesk/FBX/FBX SDK/${FBX_VERSION}") -set(FBX_SEARCH_LOCATIONS $ENV{FBX_ROOT} ${FBX_ROOT} ${FBX_MAC_LOCATIONS} ${FBX_WIN_LOCATIONS}) +set(FBX_SEARCH_LOCATIONS $ENV{FBX_ROOT} ${FBX_ROOT} ${FBX_MAC_LOCATIONS} ${FBX_WIN_LOCATIONS} ${FBX_LINUX_LOCATIONS}) function(_fbx_append_debugs _endvar _library) if (${_library} AND ${_library}_DEBUG) @@ -94,6 +95,8 @@ elseif (APPLE) find_library(SYSTEM_CONFIGURATION NAMES SystemConfiguration) _fbx_find_library(FBX_LIBRARY libfbxsdk.a release) _fbx_find_library(FBX_LIBRARY_DEBUG libfbxsdk.a debug) +else () + _fbx_find_library(FBX_LIBRARY libfbxsdk.a release) endif() include(FindPackageHandleStandardArgs) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index bdba621cb5..710fd81316 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -29,6 +29,63 @@ !include "WinVer.nsh" ;-------------------------------- +; Utilities and Functions + ;-------------------------------- + ; START String Contains Macro + ; Taken from http://nsis.sourceforge.net/StrContains + ;-------------------------------- + ; StrContains + ; This function does a case sensitive searches for an occurrence of a substring in a string. + ; It returns the substring if it is found. + ; Otherwise it returns null(""). + ; Written by kenglish_hi + ; Adapted from StrReplace written by dandaman32 + + + Var STR_HAYSTACK + Var STR_NEEDLE + Var STR_CONTAINS_VAR_1 + Var STR_CONTAINS_VAR_2 + Var STR_CONTAINS_VAR_3 + Var STR_CONTAINS_VAR_4 + Var STR_RETURN_VAR + + Function StrContains + Exch $STR_NEEDLE + Exch 1 + Exch $STR_HAYSTACK + ; Uncomment to debug + ;MessageBox MB_OK 'STR_NEEDLE = $STR_NEEDLE STR_HAYSTACK = $STR_HAYSTACK ' + StrCpy $STR_RETURN_VAR "" + StrCpy $STR_CONTAINS_VAR_1 -1 + StrLen $STR_CONTAINS_VAR_2 $STR_NEEDLE + StrLen $STR_CONTAINS_VAR_4 $STR_HAYSTACK + loop: + IntOp $STR_CONTAINS_VAR_1 $STR_CONTAINS_VAR_1 + 1 + StrCpy $STR_CONTAINS_VAR_3 $STR_HAYSTACK $STR_CONTAINS_VAR_2 $STR_CONTAINS_VAR_1 + StrCmp $STR_CONTAINS_VAR_3 $STR_NEEDLE found + StrCmp $STR_CONTAINS_VAR_1 $STR_CONTAINS_VAR_4 done + Goto loop + found: + StrCpy $STR_RETURN_VAR $STR_NEEDLE + Goto done + done: + Pop $STR_NEEDLE ;Prevent "invalid opcode" errors and keep the + Exch $STR_RETURN_VAR + FunctionEnd + + !macro _StrContainsConstructor OUT NEEDLE HAYSTACK + Push `${HAYSTACK}` + Push `${NEEDLE}` + Call StrContains + Pop `${OUT}` + !macroend + + !define StrContains '!insertmacro "_StrContainsConstructor"' + ;-------------------------------- + ; END String Contains Macro + ;-------------------------------- +;-------------------------------- ;General ; leverage the UAC NSIS plugin to promote uninstaller to elevated privileges !include UAC.nsh @@ -92,6 +149,7 @@ ; inter-component dependencies. Var AR_SecFlags Var AR_RegFlags +Var substringResult @CPACK_NSIS_SECTION_SELECTED_VARS@ ; Loads the "selected" flag for the section named SecName into the @@ -119,9 +177,11 @@ Var AR_RegFlags ClearErrors ;Reading component status from registry ReadRegDWORD $AR_RegFlags HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\Components\${SecName}" "Installed" - IfErrors "default_${SecName}" + IfErrors "checkBeforeDefault_${SecName}" ;Status will stay default if registry value not found ;(component was never installed) + + "set_initSection_${SecName}:" IntOp $AR_RegFlags $AR_RegFlags & ${SF_SELECTED} ;Turn off all other bits SectionGetFlags ${${SecName}} $AR_SecFlags ;Reading default section flags IntOp $AR_SecFlags $AR_SecFlags & 0xFFFE ;Turn lowest (enabled) bit off @@ -137,6 +197,18 @@ Var AR_RegFlags "default_${SecName}:" !insertmacro LoadSectionSelectedIntoVar ${SecName} ${SecName}_selected + Goto "end_initSection_${SecName}" + + "checkBeforeDefault_${SecName}:" + ${StrContains} $substringResult "/nSandboxIfNew" $CMDLINE + ${If} "${SecName}" == "server" + ${AndIfNot} $substringResult == "" + StrCpy $AR_RegFlags 0 + Goto "set_initSection_${SecName}" + ${Else} + Goto "default_${SecName}" + ${EndIf} + "end_initSection_${SecName}:" !macroend !macro FinishSection SecName @@ -432,6 +504,10 @@ Function PostInstallOptionsPage ; set the checkbox state depending on what is present in the registry !insertmacro SetPostInstallOption $LaunchServerNowCheckbox @SERVER_LAUNCH_NOW_REG_KEY@ ${BST_CHECKED} + ${StrContains} $substringResult "/forceNoLaunchServer" $CMDLINE + ${IfNot} $substringResult == "" + ${NSD_SetState} $LaunchServerNowCheckbox ${BST_UNCHECKED} + ${EndIf} IntOp $CurrentOffset $CurrentOffset + 15 ${EndIf} @@ -442,6 +518,10 @@ Function PostInstallOptionsPage ; set the checkbox state depending on what is present in the registry !insertmacro SetPostInstallOption $LaunchClientNowCheckbox @CLIENT_LAUNCH_NOW_REG_KEY@ ${BST_CHECKED} + ${StrContains} $substringResult "/forceNoLaunchClient" $CMDLINE + ${IfNot} $substringResult == "" + ${NSD_SetState} $LaunchClientNowCheckbox ${BST_UNCHECKED} + ${EndIf} ${EndIf} ${If} @PR_BUILD@ == 1 diff --git a/domain-server/resources/describe-settings.json b/domain-server/resources/describe-settings.json index c7dc97f595..bc67a31c02 100644 --- a/domain-server/resources/describe-settings.json +++ b/domain-server/resources/describe-settings.json @@ -1339,6 +1339,7 @@ { "name": "broadcasting", "label": "Broadcasting", + "restart": false, "settings": [ { "name": "users", @@ -1395,6 +1396,46 @@ ] } ] + }, + { + "name": "upstream_servers", + "label": "Broadcasting Servers", + "assignment-types": [0,1], + "type": "table", + "advanced": true, + "can_add_new_rows": true, + "help": "Servers that broadcast data to this domain", + "numbered": false, + "columns": [ + { + "name": "address", + "label": "Address", + "can_set": true + }, + { + "name": "port", + "label": "Port", + "can_set": true + }, + { + "name": "server_type", + "label": "Server Type", + "type": "select", + "placeholder": "Audio Mixer", + "default": "Audio Mixer", + "can_set": true, + "options": [ + { + "value": "Audio Mixer", + "label": "Audio Mixer" + }, + { + "value": "Avatar Mixer", + "label": "Avatar Mixer" + } + ] + } + ] } ] } diff --git a/domain-server/resources/web/header.html b/domain-server/resources/web/header.html index 0dc08e6e31..a37e9a6ff0 100644 --- a/domain-server/resources/web/header.html +++ b/domain-server/resources/web/header.html @@ -10,6 +10,7 @@ +