diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index 3eb093a5d4..ac283b2289 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -516,7 +516,7 @@ void Agent::setIsListeningToAudioStream(bool isListeningToAudioStream) { auto nodeList = DependencyManager::get(); nodeList->eachMatchingNode( - [&](const SharedNodePointer& node)->bool { + [](const SharedNodePointer& node)->bool { return (node->getType() == NodeType::AudioMixer) && node->getActiveSocket(); }, [&](const SharedNodePointer& node) { diff --git a/domain-server/src/DomainGatekeeper.cpp b/domain-server/src/DomainGatekeeper.cpp index 59cc8d10f6..2307b1be3b 100644 --- a/domain-server/src/DomainGatekeeper.cpp +++ b/domain-server/src/DomainGatekeeper.cpp @@ -264,7 +264,8 @@ void DomainGatekeeper::updateNodePermissions() { QList nodesToKill; auto limitedNodeList = DependencyManager::get(); - limitedNodeList->eachNode([this, limitedNodeList, &nodesToKill](const SharedNodePointer& node){ + QWeakPointer limitedNodeListWeak = limitedNodeList; + limitedNodeList->eachNode([this, limitedNodeListWeak, &nodesToKill](const SharedNodePointer& node){ // the id and the username in NodePermissions will often be the same, but id is set before // authentication and verifiedUsername is only set once they user's key has been confirmed. QString verifiedUsername = node->getPermissions().getVerifiedUserName(); @@ -296,7 +297,8 @@ void DomainGatekeeper::updateNodePermissions() { machineFingerprint = nodeData->getMachineFingerprint(); auto sendingAddress = nodeData->getSendingSockAddr().getAddress(); - isLocalUser = (sendingAddress == limitedNodeList->getLocalSockAddr().getAddress() || + auto nodeList = limitedNodeListWeak.lock(); + isLocalUser = ((nodeList && sendingAddress == nodeList->getLocalSockAddr().getAddress()) || sendingAddress == QHostAddress::LocalHost); } @@ -458,7 +460,7 @@ SharedNodePointer DomainGatekeeper::processAgentConnectRequest(const NodeConnect // in case this is a node that's failing to connect // double check we don't have the same node whose sockets match exactly already in the list - limitedNodeList->eachNodeBreakable([&](const SharedNodePointer& node){ + limitedNodeList->eachNodeBreakable([nodeConnection, username, &existingNodeID](const SharedNodePointer& node){ if (node->getPublicSocket() == nodeConnection.publicSockAddr && node->getLocalSocket() == nodeConnection.localSockAddr) { // we have a node that already has these exact sockets - this can occur if a node @@ -1009,7 +1011,7 @@ void DomainGatekeeper::refreshGroupsCache() { getDomainOwnerFriendsList(); auto nodeList = DependencyManager::get(); - nodeList->eachNode([&](const SharedNodePointer& node) { + nodeList->eachNode([this](const SharedNodePointer& node) { if (!node->getPermissions().isAssignment) { // this node is an agent const QString& verifiedUserName = node->getPermissions().getVerifiedUserName(); diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index b7abe9e03f..c6b387c937 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -1078,7 +1078,7 @@ bool DomainServer::isInInterestSet(const SharedNodePointer& nodeA, const SharedN unsigned int DomainServer::countConnectedUsers() { unsigned int result = 0; auto nodeList = DependencyManager::get(); - nodeList->eachNode([&](const SharedNodePointer& node){ + nodeList->eachNode([&result](const SharedNodePointer& node){ // only count unassigned agents (i.e., users) if (node->getType() == NodeType::Agent) { auto nodeData = static_cast(node->getLinkedData()); @@ -1181,7 +1181,7 @@ void DomainServer::sendDomainListToNode(const SharedNodePointer& node, const Hif // DTLSServerSession* dtlsSession = _isUsingDTLS ? _dtlsSessions[senderSockAddr] : NULL; if (nodeData->isAuthenticated()) { // if this authenticated node has any interest types, send back those nodes as well - limitedNodeList->eachNode([&](const SharedNodePointer& otherNode) { + limitedNodeList->eachNode([this, node, &domainListPackets, &domainListStream](const SharedNodePointer& otherNode) { if (otherNode->getUUID() != node->getUUID() && isInInterestSet(node, otherNode)) { // since we're about to add a node to the packet we start a segment domainListPackets->startSegment(); @@ -1230,6 +1230,7 @@ QUuid DomainServer::connectionSecretForNodes(const SharedNodePointer& nodeA, con void DomainServer::broadcastNewNode(const SharedNodePointer& addedNode) { auto limitedNodeList = DependencyManager::get(); + QWeakPointer limitedNodeListWeak = limitedNodeList; auto addNodePacket = NLPacket::create(PacketType::DomainServerAddedNode); @@ -1241,7 +1242,7 @@ void DomainServer::broadcastNewNode(const SharedNodePointer& addedNode) { int connectionSecretIndex = addNodePacket->pos(); limitedNodeList->eachMatchingNode( - [&](const SharedNodePointer& node)->bool { + [this, addedNode](const SharedNodePointer& node)->bool { if (node->getLinkedData() && node->getActiveSocket() && node != addedNode) { // is the added Node in this node's interest list? return isInInterestSet(node, addedNode); @@ -1249,16 +1250,19 @@ void DomainServer::broadcastNewNode(const SharedNodePointer& addedNode) { return false; } }, - [&](const SharedNodePointer& node) { - addNodePacket->seek(connectionSecretIndex); - - QByteArray rfcConnectionSecret = connectionSecretForNodes(node, addedNode).toRfc4122(); - - // replace the bytes at the end of the packet for the connection secret between these nodes - addNodePacket->write(rfcConnectionSecret); - + [this, &addNodePacket, connectionSecretIndex, addedNode, limitedNodeListWeak](const SharedNodePointer& node) { // send off this packet to the node - limitedNodeList->sendUnreliablePacket(*addNodePacket, *node); + auto limitedNodeList = limitedNodeListWeak.lock(); + if (limitedNodeList) { + addNodePacket->seek(connectionSecretIndex); + + QByteArray rfcConnectionSecret = connectionSecretForNodes(node, addedNode).toRfc4122(); + + // replace the bytes at the end of the packet for the connection secret between these nodes + addNodePacket->write(rfcConnectionSecret); + + limitedNodeList->sendUnreliablePacket(*addNodePacket, *node); + } } ); } @@ -2864,7 +2868,7 @@ void DomainServer::updateReplicationNodes(ReplicationServerDirection direction) auto serversSettings = replicationSettings.value(serversKey).toList(); std::vector knownReplicationNodes; - nodeList->eachNode([&](const SharedNodePointer& otherNode) { + nodeList->eachNode([direction, &knownReplicationNodes](const SharedNodePointer& otherNode) { if ((direction == Upstream && NodeType::isUpstream(otherNode->getType())) || (direction == Downstream && NodeType::isDownstream(otherNode->getType()))) { knownReplicationNodes.push_back(otherNode->getPublicSocket()); @@ -2902,7 +2906,7 @@ void DomainServer::updateReplicationNodes(ReplicationServerDirection direction) // collect them in a vector to separately remove them with handleKillNode (since eachNode has a read lock and // we cannot recursively take the write lock required by handleKillNode) std::vector nodesToKill; - nodeList->eachNode([&](const SharedNodePointer& otherNode) { + nodeList->eachNode([this, direction, replicationNodesInSettings, replicationDirection, &nodesToKill](const SharedNodePointer& otherNode) { if ((direction == Upstream && NodeType::isUpstream(otherNode->getType())) || (direction == Downstream && NodeType::isDownstream(otherNode->getType()))) { bool nodeInSettings = find(replicationNodesInSettings.cbegin(), replicationNodesInSettings.cend(), diff --git a/interface/src/AboutUtil.cpp b/interface/src/AboutUtil.cpp index 634e52b481..56cabce03d 100644 --- a/interface/src/AboutUtil.cpp +++ b/interface/src/AboutUtil.cpp @@ -45,9 +45,7 @@ QString AboutUtil::getQtVersion() const { } void AboutUtil::openUrl(const QString& url) const { - - auto tabletScriptingInterface = DependencyManager::get(); - auto tablet = tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system"); + auto tablet = DependencyManager::get()->getTablet("com.highfidelity.interface.tablet.system"); auto hmd = DependencyManager::get(); auto offscreenUi = DependencyManager::get(); diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 57c2dfb212..45ef336333 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1139,8 +1139,10 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo // setup a timer for domain-server check ins QTimer* domainCheckInTimer = new QTimer(this); - connect(domainCheckInTimer, &QTimer::timeout, [this, nodeList] { - if (!isServerlessMode()) { + QWeakPointer nodeListWeak = nodeList; + connect(domainCheckInTimer, &QTimer::timeout, [this, nodeListWeak] { + auto nodeList = nodeListWeak.lock(); + if (!isServerlessMode() && nodeList) { nodeList->sendDomainServerCheckIn(); } }); @@ -1150,33 +1152,34 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo domainCheckInTimer->deleteLater(); }); + { + auto audioIO = DependencyManager::get().data(); + audioIO->setPositionGetter([] { + auto avatarManager = DependencyManager::get(); + auto myAvatar = avatarManager ? avatarManager->getMyAvatar() : nullptr; - auto audioIO = DependencyManager::get(); - audioIO->setPositionGetter([]{ - auto avatarManager = DependencyManager::get(); - auto myAvatar = avatarManager ? avatarManager->getMyAvatar() : nullptr; + return myAvatar ? myAvatar->getPositionForAudio() : Vectors::ZERO; + }); + audioIO->setOrientationGetter([] { + auto avatarManager = DependencyManager::get(); + auto myAvatar = avatarManager ? avatarManager->getMyAvatar() : nullptr; - return myAvatar ? myAvatar->getPositionForAudio() : Vectors::ZERO; - }); - audioIO->setOrientationGetter([]{ - auto avatarManager = DependencyManager::get(); - auto myAvatar = avatarManager ? avatarManager->getMyAvatar() : nullptr; + return myAvatar ? myAvatar->getOrientationForAudio() : Quaternions::IDENTITY; + }); - return myAvatar ? myAvatar->getOrientationForAudio() : Quaternions::IDENTITY; - }); + recording::Frame::registerFrameHandler(AudioConstants::getAudioFrameName(), [&audioIO](recording::Frame::ConstPointer frame) { + audioIO->handleRecordedAudioInput(frame->data); + }); - recording::Frame::registerFrameHandler(AudioConstants::getAudioFrameName(), [=](recording::Frame::ConstPointer frame) { - audioIO->handleRecordedAudioInput(frame->data); - }); - - connect(audioIO.data(), &AudioClient::inputReceived, [](const QByteArray& audio){ - static auto recorder = DependencyManager::get(); - if (recorder->isRecording()) { - static const recording::FrameType AUDIO_FRAME_TYPE = recording::Frame::registerFrameType(AudioConstants::getAudioFrameName()); - recorder->recordFrame(AUDIO_FRAME_TYPE, audio); - } - }); - audioIO->startThread(); + connect(audioIO, &AudioClient::inputReceived, [](const QByteArray& audio) { + static auto recorder = DependencyManager::get(); + if (recorder->isRecording()) { + static const recording::FrameType AUDIO_FRAME_TYPE = recording::Frame::registerFrameType(AudioConstants::getAudioFrameName()); + recorder->recordFrame(AUDIO_FRAME_TYPE, audio); + } + }); + audioIO->startThread(); + } // Make sure we don't time out during slow operations at startup updateHeartbeat(); @@ -1275,27 +1278,29 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo // Inititalize sample before registering _sampleSound = DependencyManager::get()->getSound(PathUtils::resourcesUrl("sounds/sample.wav")); - auto scriptEngines = DependencyManager::get().data(); - scriptEngines->registerScriptInitializer([this](ScriptEnginePointer engine){ - registerScriptEngineWithApplicationServices(engine); - }); + { + auto scriptEngines = DependencyManager::get().data(); + scriptEngines->registerScriptInitializer([this](ScriptEnginePointer engine) { + registerScriptEngineWithApplicationServices(engine); + }); - connect(scriptEngines, &ScriptEngines::scriptCountChanged, scriptEngines, [this] { - auto scriptEngines = DependencyManager::get(); - if (scriptEngines->getRunningScripts().isEmpty()) { - getMyAvatar()->clearScriptableSettings(); - } - }, Qt::QueuedConnection); + connect(scriptEngines, &ScriptEngines::scriptCountChanged, this, [this] { + auto scriptEngines = DependencyManager::get(); + if (scriptEngines->getRunningScripts().isEmpty()) { + getMyAvatar()->clearScriptableSettings(); + } + }, Qt::QueuedConnection); - connect(scriptEngines, &ScriptEngines::scriptsReloading, scriptEngines, [this] { - getEntities()->reloadEntityScripts(); - loadAvatarScripts(getMyAvatar()->getScriptUrls()); - }, Qt::QueuedConnection); + connect(scriptEngines, &ScriptEngines::scriptsReloading, this, [this] { + getEntities()->reloadEntityScripts(); + loadAvatarScripts(getMyAvatar()->getScriptUrls()); + }, Qt::QueuedConnection); - connect(scriptEngines, &ScriptEngines::scriptLoadError, - scriptEngines, [](const QString& filename, const QString& error){ - OffscreenUi::asyncWarning(nullptr, "Error Loading Script", filename + " failed to load."); - }, Qt::QueuedConnection); + connect(scriptEngines, &ScriptEngines::scriptLoadError, + this, [](const QString& filename, const QString& error) { + OffscreenUi::asyncWarning(nullptr, "Error Loading Script", filename + " failed to load."); + }, Qt::QueuedConnection); + } #ifdef _WIN32 WSADATA WsaData; @@ -1365,10 +1370,11 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo // so we defer the setup of the `scripting::Audio` class until this point { auto audioScriptingInterface = DependencyManager::set(); - connect(audioIO.data(), &AudioClient::mutedByMixer, audioScriptingInterface.data(), &AudioScriptingInterface::mutedByMixer); - connect(audioIO.data(), &AudioClient::receivedFirstPacket, audioScriptingInterface.data(), &AudioScriptingInterface::receivedFirstPacket); - connect(audioIO.data(), &AudioClient::disconnected, audioScriptingInterface.data(), &AudioScriptingInterface::disconnected); - connect(audioIO.data(), &AudioClient::muteEnvironmentRequested, [](glm::vec3 position, float radius) { + auto audioIO = DependencyManager::get().data(); + connect(audioIO, &AudioClient::mutedByMixer, audioScriptingInterface.data(), &AudioScriptingInterface::mutedByMixer); + connect(audioIO, &AudioClient::receivedFirstPacket, audioScriptingInterface.data(), &AudioScriptingInterface::receivedFirstPacket); + connect(audioIO, &AudioClient::disconnected, audioScriptingInterface.data(), &AudioScriptingInterface::disconnected); + connect(audioIO, &AudioClient::muteEnvironmentRequested, [](glm::vec3 position, float radius) { auto audioClient = DependencyManager::get(); auto audioScriptingInterface = DependencyManager::get(); auto myAvatarPosition = DependencyManager::get()->getMyAvatar()->getWorldPosition(); @@ -1697,23 +1703,26 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo userInputMapper->registerDevice(_touchscreenVirtualPadDevice->getInputDevice()); } - // this will force the model the look at the correct directory (weird order of operations issue) - scriptEngines->reloadLocalFiles(); + { + auto scriptEngines = DependencyManager::get().data(); + // this will force the model the look at the correct directory (weird order of operations issue) + scriptEngines->reloadLocalFiles(); - // do this as late as possible so that all required subsystems are initialized - // If we've overridden the default scripts location, just load default scripts - // otherwise, load 'em all + // do this as late as possible so that all required subsystems are initialized + // If we've overridden the default scripts location, just load default scripts + // otherwise, load 'em all - // we just want to see if --scripts was set, we've already parsed it and done - // the change in PathUtils. Rather than pass that in the constructor, lets just - // look (this could be debated) - QString scriptsSwitch = QString("--").append(SCRIPTS_SWITCH); - QDir defaultScriptsLocation(getCmdOption(argc, constArgv, scriptsSwitch.toStdString().c_str())); - if (!defaultScriptsLocation.exists()) { - scriptEngines->loadDefaultScripts(); - scriptEngines->defaultScriptsLocationOverridden(true); - } else { - scriptEngines->loadScripts(); + // we just want to see if --scripts was set, we've already parsed it and done + // the change in PathUtils. Rather than pass that in the constructor, lets just + // look (this could be debated) + QString scriptsSwitch = QString("--").append(SCRIPTS_SWITCH); + QDir defaultScriptsLocation(getCmdOption(argc, constArgv, scriptsSwitch.toStdString().c_str())); + if (!defaultScriptsLocation.exists()) { + scriptEngines->loadDefaultScripts(); + scriptEngines->defaultScriptsLocationOverridden(true); + } else { + scriptEngines->loadScripts(); + } } // Make sure we don't time out during slow operations at startup @@ -1763,13 +1772,16 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo cameraMenuChanged(); } - // set the local loopback interface for local sounds - AudioInjector::setLocalAudioInterface(audioIO.data()); - auto audioScriptingInterface = DependencyManager::get(); - audioScriptingInterface->setLocalAudioInterface(audioIO.data()); - connect(audioIO.data(), &AudioClient::noiseGateOpened, audioScriptingInterface.data(), &AudioScriptingInterface::noiseGateOpened); - connect(audioIO.data(), &AudioClient::noiseGateClosed, audioScriptingInterface.data(), &AudioScriptingInterface::noiseGateClosed); - connect(audioIO.data(), &AudioClient::inputReceived, audioScriptingInterface.data(), &AudioScriptingInterface::inputReceived); + { + auto audioIO = DependencyManager::get().data(); + // set the local loopback interface for local sounds + AudioInjector::setLocalAudioInterface(audioIO); + auto audioScriptingInterface = DependencyManager::get(); + audioScriptingInterface->setLocalAudioInterface(audioIO); + connect(audioIO, &AudioClient::noiseGateOpened, audioScriptingInterface.data(), &AudioScriptingInterface::noiseGateOpened); + connect(audioIO, &AudioClient::noiseGateClosed, audioScriptingInterface.data(), &AudioScriptingInterface::noiseGateClosed); + connect(audioIO, &AudioClient::inputReceived, audioScriptingInterface.data(), &AudioScriptingInterface::inputReceived); + } this->installEventFilter(this); @@ -1826,13 +1838,13 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo } }); - connect(entityScriptingInterface.data(), &EntityScriptingInterface::deletingEntity, [=](const EntityItemID& entityItemID) { + connect(entityScriptingInterface.data(), &EntityScriptingInterface::deletingEntity, [this](const EntityItemID& entityItemID) { if (entityItemID == _keyboardFocusedEntity.get()) { setKeyboardFocusEntity(UNKNOWN_ENTITY_ID); } }); - connect(getEntities()->getTree().get(), &EntityTree::deletingEntity, [=](const EntityItemID& entityItemID) { + connect(getEntities()->getTree().get(), &EntityTree::deletingEntity, [](const EntityItemID& entityItemID) { auto avatarManager = DependencyManager::get(); auto myAvatar = avatarManager ? avatarManager->getMyAvatar() : nullptr; if (myAvatar) { @@ -1840,7 +1852,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo } }); - EntityTree::setAddMaterialToEntityOperator([&](const QUuid& entityID, graphics::MaterialLayer material, const std::string& parentMaterialName) { + EntityTree::setAddMaterialToEntityOperator([this](const QUuid& entityID, graphics::MaterialLayer material, const std::string& parentMaterialName) { // try to find the renderable auto renderable = getEntities()->renderableForEntityId(entityID); if (renderable) { @@ -1855,7 +1867,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo } return false; }); - EntityTree::setRemoveMaterialFromEntityOperator([&](const QUuid& entityID, graphics::MaterialPointer material, const std::string& parentMaterialName) { + EntityTree::setRemoveMaterialFromEntityOperator([this](const QUuid& entityID, graphics::MaterialPointer material, const std::string& parentMaterialName) { // try to find the renderable auto renderable = getEntities()->renderableForEntityId(entityID); if (renderable) { @@ -1890,7 +1902,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo return false; }); - EntityTree::setAddMaterialToOverlayOperator([&](const QUuid& overlayID, graphics::MaterialLayer material, const std::string& parentMaterialName) { + EntityTree::setAddMaterialToOverlayOperator([this](const QUuid& overlayID, graphics::MaterialLayer material, const std::string& parentMaterialName) { auto overlay = _overlays.getOverlay(overlayID); if (overlay) { overlay->addMaterial(material, parentMaterialName); @@ -1898,7 +1910,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo } return false; }); - EntityTree::setRemoveMaterialFromOverlayOperator([&](const QUuid& overlayID, graphics::MaterialPointer material, const std::string& parentMaterialName) { + EntityTree::setRemoveMaterialFromOverlayOperator([this](const QUuid& overlayID, graphics::MaterialPointer material, const std::string& parentMaterialName) { auto overlay = _overlays.getOverlay(overlayID); if (overlay) { overlay->removeMaterial(material, parentMaterialName); @@ -1909,13 +1921,13 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo // Keyboard focus handling for Web overlays. auto overlays = &(qApp->getOverlays()); - connect(overlays, &Overlays::overlayDeleted, [=](const OverlayID& overlayID) { + connect(overlays, &Overlays::overlayDeleted, [this](const OverlayID& overlayID) { if (overlayID == _keyboardFocusedOverlay.get()) { setKeyboardFocusOverlay(UNKNOWN_OVERLAY_ID); } }); - connect(this, &Application::aboutToQuit, [=]() { + connect(this, &Application::aboutToQuit, [this]() { setKeyboardFocusOverlay(UNKNOWN_OVERLAY_ID); setKeyboardFocusEntity(UNKNOWN_ENTITY_ID); }); @@ -2184,23 +2196,22 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo QVariant testProperty = property(hifi::properties::TEST); qDebug() << testProperty; if (testProperty.isValid()) { - auto scriptEngines = DependencyManager::get(); const auto testScript = property(hifi::properties::TEST).toUrl(); // Set last parameter to exit interface when the test script finishes, if so requested - scriptEngines->loadScript(testScript, false, false, false, false, quitWhenFinished); + DependencyManager::get()->loadScript(testScript, false, false, false, false, quitWhenFinished); // This is done so we don't get a "connection time-out" message when we haven't passed in a URL. if (arguments().contains("--url")) { auto reply = SandboxUtils::getStatus(); - connect(reply, &QNetworkReply::finished, this, [=] { + connect(reply, &QNetworkReply::finished, this, [this, reply] { handleSandboxStatus(reply); }); } } else { PROFILE_RANGE(render, "GetSandboxStatus"); auto reply = SandboxUtils::getStatus(); - connect(reply, &QNetworkReply::finished, this, [=] { + connect(reply, &QNetworkReply::finished, this, [this, reply] { handleSandboxStatus(reply); }); } @@ -2227,8 +2238,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo connect(&_myCamera, &Camera::modeUpdated, this, &Application::cameraModeChanged); - DependencyManager::get()->setShouldPickHUDOperator([&]() { return DependencyManager::get()->isHMDMode(); }); - DependencyManager::get()->setCalculatePos2DFromHUDOperator([&](const glm::vec3& intersection) { + DependencyManager::get()->setShouldPickHUDOperator([]() { return DependencyManager::get()->isHMDMode(); }); + DependencyManager::get()->setCalculatePos2DFromHUDOperator([this](const glm::vec3& intersection) { const glm::vec2 MARGIN(25.0f); glm::vec2 maxPos = _controllerScriptingInterface->getViewportDimensions() - MARGIN; glm::vec2 pos2D = DependencyManager::get()->overlayFromWorldPoint(intersection); @@ -2238,7 +2249,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo // Setup the mouse ray pick and related operators DependencyManager::get()->setMouseRayPickID(DependencyManager::get()->addPick(PickQuery::Ray, std::make_shared( PickFilter(PickScriptingInterface::PICK_ENTITIES() | PickScriptingInterface::PICK_INCLUDE_NONCOLLIDABLE()), 0.0f, true))); - DependencyManager::get()->setMouseRayPickResultOperator([&](unsigned int rayPickID) { + DependencyManager::get()->setMouseRayPickResultOperator([](unsigned int rayPickID) { RayToEntityIntersectionResult entityResult; entityResult.intersects = false; auto pickResult = DependencyManager::get()->getPrevPickResultTyped(rayPickID); @@ -2254,7 +2265,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo } return entityResult; }); - DependencyManager::get()->setSetPrecisionPickingOperator([&](unsigned int rayPickID, bool value) { + DependencyManager::get()->setSetPrecisionPickingOperator([](unsigned int rayPickID, bool value) { DependencyManager::get()->setPrecisionPicking(rayPickID, value); }); @@ -2453,21 +2464,35 @@ void Application::cleanupBeforeQuit() { _keyboardFocusHighlight = nullptr; } - auto nodeList = DependencyManager::get(); + { + auto nodeList = DependencyManager::get(); - // send the domain a disconnect packet, force stoppage of domain-server check-ins - nodeList->getDomainHandler().disconnect(); - nodeList->setIsShuttingDown(true); + // send the domain a disconnect packet, force stoppage of domain-server check-ins + nodeList->getDomainHandler().disconnect(); + nodeList->setIsShuttingDown(true); - // tell the packet receiver we're shutting down, so it can drop packets - nodeList->getPacketReceiver().setShouldDropPackets(true); + // tell the packet receiver we're shutting down, so it can drop packets + nodeList->getPacketReceiver().setShouldDropPackets(true); + } getEntities()->shutdown(); // tell the entities system we're shutting down, so it will stop running scripts // Clear any queued processing (I/O, FBX/OBJ/Texture parsing) QThreadPool::globalInstance()->clear(); + DependencyManager::destroy(); + + // FIXME: Something is still holding on to the ScriptEnginePointers contained in ScriptEngines, and they hold backpointers to ScriptEngines, + // so this doesn't shut down properly DependencyManager::get()->shutdownScripting(); // stop all currently running global scripts + // These classes hold ScriptEnginePointers, so they must be destroyed before ScriptEngines + // Must be done after shutdownScripting in case any scripts try to access these things + { + DependencyManager::destroy(); + EntityTreePointer tree = getEntities()->getTree(); + tree->setSimulation(nullptr); + DependencyManager::destroy(); + } DependencyManager::destroy(); _displayPlugin.reset(); @@ -2504,6 +2529,8 @@ void Application::cleanupBeforeQuit() { DependencyManager::destroy(); #endif + DependencyManager::destroy(); // Must be destroyed before TabletScriptingInterface + // stop QML DependencyManager::destroy(); DependencyManager::destroy(); @@ -2515,10 +2542,6 @@ void Application::cleanupBeforeQuit() { _snapshotSoundInjector->stop(); } - // FIXME: something else is holding a reference to AudioClient, - // so it must be explicitly synchronously stopped here - DependencyManager::get()->cleanupBeforeQuit(); - // destroy Audio so it and its threads have a chance to go down safely // this must happen after QML, as there are unexplained audio crashes originating in qtwebengine DependencyManager::destroy(); @@ -2558,9 +2581,6 @@ Application::~Application() { _entityClipboard->eraseAllOctreeElements(); _entityClipboard.reset(); - EntityTreePointer tree = getEntities()->getTree(); - tree->setSimulation(nullptr); - _octreeProcessor.terminate(); _entityEditSender.terminate(); @@ -3274,8 +3294,7 @@ void Application::showHelp() { QUrlQuery queryString; queryString.addQueryItem("handControllerName", handControllerName); queryString.addQueryItem("defaultTab", defaultTab); - auto tabletScriptingInterface = DependencyManager::get(); - TabletProxy* tablet = dynamic_cast(tabletScriptingInterface->getTablet(SYSTEM_TABLET)); + TabletProxy* tablet = dynamic_cast(DependencyManager::get()->getTablet(SYSTEM_TABLET)); tablet->gotoWebScreen(PathUtils::resourcesUrl() + INFO_HELP_PATH + "?" + queryString.toString()); DependencyManager::get()->openTablet(); //InfoView::show(INFO_HELP_PATH, false, queryString.toString()); @@ -3588,6 +3607,10 @@ static void dumpEventQueue(QThread* thread) { bool Application::event(QEvent* event) { + if (_aboutToQuit) { + return false; + } + if (!Menu::getInstance()) { return false; } @@ -3992,10 +4015,6 @@ void Application::maybeToggleMenuVisible(QMouseEvent* event) const { void Application::mouseMoveEvent(QMouseEvent* event) { PROFILE_RANGE(app_input_mouse, __FUNCTION__); - if (_aboutToQuit) { - return; - } - maybeToggleMenuVisible(event); auto& compositor = getApplicationCompositor(); @@ -4060,11 +4079,9 @@ void Application::mousePressEvent(QMouseEvent* event) { event->screenPos(), event->button(), event->buttons(), event->modifiers()); - if (!_aboutToQuit) { - getOverlays().mousePressEvent(&mappedEvent); - if (!_controllerScriptingInterface->areEntityClicksCaptured()) { - getEntities()->mousePressEvent(&mappedEvent); - } + getOverlays().mousePressEvent(&mappedEvent); + if (!_controllerScriptingInterface->areEntityClicksCaptured()) { + getEntities()->mousePressEvent(&mappedEvent); } _controllerScriptingInterface->emitMousePressEvent(&mappedEvent); // send events to any registered scripts @@ -4101,14 +4118,11 @@ void Application::mouseDoublePressEvent(QMouseEvent* event) { event->screenPos(), event->button(), event->buttons(), event->modifiers()); - if (!_aboutToQuit) { - getOverlays().mouseDoublePressEvent(&mappedEvent); - if (!_controllerScriptingInterface->areEntityClicksCaptured()) { - getEntities()->mouseDoublePressEvent(&mappedEvent); - } + getOverlays().mouseDoublePressEvent(&mappedEvent); + if (!_controllerScriptingInterface->areEntityClicksCaptured()) { + getEntities()->mouseDoublePressEvent(&mappedEvent); } - // if one of our scripts have asked to capture this event, then stop processing it if (_controllerScriptingInterface->isMouseCaptured()) { return; @@ -4127,10 +4141,8 @@ void Application::mouseReleaseEvent(QMouseEvent* event) { event->screenPos(), event->button(), event->buttons(), event->modifiers()); - if (!_aboutToQuit) { - getOverlays().mouseReleaseEvent(&mappedEvent); - getEntities()->mouseReleaseEvent(&mappedEvent); - } + getOverlays().mouseReleaseEvent(&mappedEvent); + getEntities()->mouseReleaseEvent(&mappedEvent); _controllerScriptingInterface->emitMouseReleaseEvent(&mappedEvent); // send events to any registered scripts @@ -4281,7 +4293,6 @@ bool Application::shouldPaint() const { return false; } - auto displayPlugin = getActiveDisplayPlugin(); #ifdef DEBUG_PAINT_DELAY @@ -4761,7 +4772,7 @@ bool Application::exportEntities(const QString& filename, exportTree->createRootElement(); glm::vec3 root(TREE_SCALE, TREE_SCALE, TREE_SCALE); bool success = true; - entityTree->withReadLock([&] { + entityTree->withReadLock([entityIDs, entityTree, givenOffset, myAvatarID, &root, &entities, &success, &exportTree] { for (auto entityID : entityIDs) { // Gather entities and properties. auto entityItem = entityTree->findEntityByEntityItemID(entityID); if (!entityItem) { @@ -5510,6 +5521,10 @@ static bool domainLoadingInProgress = false; void Application::update(float deltaTime) { PROFILE_RANGE_EX(app, __FUNCTION__, 0xffff0000, (uint64_t)_renderFrameCount + 1); + if (_aboutToQuit) { + return; + } + if (!_physicsEnabled) { if (!domainLoadingInProgress) { PROFILE_ASYNC_BEGIN(app, "Scene Loading", ""); @@ -5778,15 +5793,13 @@ void Application::update(float deltaTime) { _entitySimulation->handleDeactivatedMotionStates(deactivations); }); - if (!_aboutToQuit) { - // handleCollisionEvents() AFTER handleChangedMotionStates() - { - PROFILE_RANGE(simulation_physics, "CollisionEvents"); - avatarManager->handleCollisionEvents(collisionEvents); - // Collision events (and their scripts) must not be handled when we're locked, above. (That would risk - // deadlock.) - _entitySimulation->handleCollisionEvents(collisionEvents); - } + // handleCollisionEvents() AFTER handleChangedMotionStates() + { + PROFILE_RANGE(simulation_physics, "CollisionEvents"); + avatarManager->handleCollisionEvents(collisionEvents); + // Collision events (and their scripts) must not be handled when we're locked, above. (That would risk + // deadlock.) + _entitySimulation->handleCollisionEvents(collisionEvents); } { @@ -5804,11 +5817,9 @@ void Application::update(float deltaTime) { } auto t4 = std::chrono::high_resolution_clock::now(); - if (!_aboutToQuit) { - // NOTE: the getEntities()->update() call below will wait for lock - // and will provide non-physical entity motion - getEntities()->update(true); // update the models... - } + // NOTE: the getEntities()->update() call below will wait for lock + // and will provide non-physical entity motion + getEntities()->update(true); // update the models... auto t5 = std::chrono::high_resolution_clock::now(); @@ -6374,7 +6385,6 @@ void Application::domainURLChanged(QUrl domainURL) { void Application::resettingDomain() { _notifiedPacketVersionMismatchThisDomain = false; - auto nodeList = DependencyManager::get(); clearDomainOctreeDetails(); } @@ -6729,16 +6739,12 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEnginePointe pickScriptingInterface->registerMetaTypes(scriptEngine.data()); // connect this script engines printedMessage signal to the global ScriptEngines these various messages - connect(scriptEngine.data(), &ScriptEngine::printedMessage, - DependencyManager::get().data(), &ScriptEngines::onPrintedMessage); - connect(scriptEngine.data(), &ScriptEngine::errorMessage, - DependencyManager::get().data(), &ScriptEngines::onErrorMessage); - connect(scriptEngine.data(), &ScriptEngine::warningMessage, - DependencyManager::get().data(), &ScriptEngines::onWarningMessage); - connect(scriptEngine.data(), &ScriptEngine::infoMessage, - DependencyManager::get().data(), &ScriptEngines::onInfoMessage); - connect(scriptEngine.data(), &ScriptEngine::clearDebugWindow, - DependencyManager::get().data(), &ScriptEngines::onClearDebugWindow); + auto scriptEngines = DependencyManager::get().data(); + connect(scriptEngine.data(), &ScriptEngine::printedMessage, scriptEngines, &ScriptEngines::onPrintedMessage); + connect(scriptEngine.data(), &ScriptEngine::errorMessage, scriptEngines, &ScriptEngines::onErrorMessage); + connect(scriptEngine.data(), &ScriptEngine::warningMessage, scriptEngines, &ScriptEngines::onWarningMessage); + connect(scriptEngine.data(), &ScriptEngine::infoMessage, scriptEngines, &ScriptEngines::onInfoMessage); + connect(scriptEngine.data(), &ScriptEngine::clearDebugWindow, scriptEngines, &ScriptEngines::onClearDebugWindow); } @@ -7046,10 +7052,9 @@ void Application::showDialog(const QUrl& widgetUrl, const QUrl& tabletUrl, const } void Application::showScriptLogs() { - auto scriptEngines = DependencyManager::get(); QUrl defaultScriptsLoc = PathUtils::defaultScriptsLocation(); defaultScriptsLoc.setPath(defaultScriptsLoc.path() + "developer/debugging/debugWindow.js"); - scriptEngines->loadScript(defaultScriptsLoc.toString()); + DependencyManager::get()->loadScript(defaultScriptsLoc.toString()); } void Application::showAssetServerWidget(QString filePath) { @@ -7615,7 +7620,6 @@ void Application::openUrl(const QUrl& url) const { } void Application::loadDialog() { - auto scriptEngines = DependencyManager::get(); ModalDialogListener* dlg = OffscreenUi::getOpenFileNameAsync(_glWidget, tr("Open Script"), getPreviousScriptLocation(), tr("JavaScript Files (*.js)")); diff --git a/interface/src/AvatarBookmarks.cpp b/interface/src/AvatarBookmarks.cpp index 89097f3435..6afab71c90 100644 --- a/interface/src/AvatarBookmarks.cpp +++ b/interface/src/AvatarBookmarks.cpp @@ -64,7 +64,7 @@ void addAvatarEntities(const QVariantList& avatarEntities) { EntityItemID id = EntityItemID(QUuid::createUuid()); bool success = true; - entityTree->withWriteLock([&] { + entityTree->withWriteLock([&entityTree, id, &entityProperties, &success] { EntityItemPointer entity = entityTree->addEntity(id, entityProperties); if (entity) { if (entityProperties.queryAACubeRelatedPropertyChanged()) { diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 130c2c0b89..2c364154f7 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -147,9 +147,11 @@ Menu::Menu() { auto assetServerAction = addActionToQMenuAndActionHash(editMenu, MenuOption::AssetServer, Qt::CTRL | Qt::SHIFT | Qt::Key_A, qApp, SLOT(showAssetServerWidget())); - auto nodeList = DependencyManager::get(); - QObject::connect(nodeList.data(), &NodeList::canWriteAssetsChanged, assetServerAction, &QAction::setEnabled); - assetServerAction->setEnabled(nodeList->getThisNodeCanWriteAssets()); + { + auto nodeList = DependencyManager::get(); + QObject::connect(nodeList.data(), &NodeList::canWriteAssetsChanged, assetServerAction, &QAction::setEnabled); + assetServerAction->setEnabled(nodeList->getThisNodeCanWriteAssets()); + } // Edit > Package Model as .fst... addActionToQMenuAndActionHash(editMenu, MenuOption::PackageModel, 0, @@ -620,8 +622,11 @@ Menu::Menu() { addCheckableActionToQMenuAndActionHash(networkMenu, MenuOption::SendWrongProtocolVersion, 0, false, qApp, SLOT(sendWrongProtocolVersionsSignature(bool))); - addCheckableActionToQMenuAndActionHash(networkMenu, MenuOption::SendWrongDSConnectVersion, 0, false, - nodeList.data(), SLOT(toggleSendNewerDSConnectVersion(bool))); + { + auto nodeList = DependencyManager::get(); + addCheckableActionToQMenuAndActionHash(networkMenu, MenuOption::SendWrongDSConnectVersion, 0, false, + nodeList.data(), SLOT(toggleSendNewerDSConnectVersion(bool))); + } #endif @@ -655,10 +660,9 @@ Menu::Menu() { action = addActionToQMenuAndActionHash(audioDebugMenu, "Stats..."); connect(action, &QAction::triggered, [] { - auto scriptEngines = DependencyManager::get(); QUrl defaultScriptsLoc = PathUtils::defaultScriptsLocation(); defaultScriptsLoc.setPath(defaultScriptsLoc.path() + "developer/utilities/audio/stats.js"); - scriptEngines->loadScript(defaultScriptsLoc.toString()); + DependencyManager::get()->loadScript(defaultScriptsLoc.toString()); }); action = addActionToQMenuAndActionHash(audioDebugMenu, "Buffers..."); @@ -667,16 +671,14 @@ Menu::Menu() { QString("hifi/tablet/TabletAudioBuffers.qml"), "AudioBuffersDialog"); }); - auto audioIO = DependencyManager::get(); addActionToQMenuAndActionHash(audioDebugMenu, MenuOption::MuteEnvironment, 0, - audioIO.data(), SLOT(sendMuteEnvironmentPacket())); + DependencyManager::get().data(), SLOT(sendMuteEnvironmentPacket())); action = addActionToQMenuAndActionHash(audioDebugMenu, MenuOption::AudioScope); connect(action, &QAction::triggered, [] { - auto scriptEngines = DependencyManager::get(); QUrl defaultScriptsLoc = PathUtils::defaultScriptsLocation(); defaultScriptsLoc.setPath(defaultScriptsLoc.path() + "developer/utilities/audio/audioScope.js"); - scriptEngines->loadScript(defaultScriptsLoc.toString()); + DependencyManager::get()->loadScript(defaultScriptsLoc.toString()); }); // Developer > Physics >>> @@ -756,10 +758,9 @@ Menu::Menu() { // Developer > API Debugger action = addActionToQMenuAndActionHash(developerMenu, "API Debugger"); connect(action, &QAction::triggered, [] { - auto scriptEngines = DependencyManager::get(); QUrl defaultScriptsLoc = PathUtils::defaultScriptsLocation(); defaultScriptsLoc.setPath(defaultScriptsLoc.path() + "developer/utilities/tools/currentAPI.js"); - scriptEngines->loadScript(defaultScriptsLoc.toString()); + DependencyManager::get()->loadScript(defaultScriptsLoc.toString()); }); // Developer > Log... @@ -767,11 +768,14 @@ Menu::Menu() { qApp, SLOT(toggleLogDialog())); auto essLogAction = addActionToQMenuAndActionHash(developerMenu, MenuOption::EntityScriptServerLog, 0, qApp, SLOT(toggleEntityScriptServerLogDialog())); - QObject::connect(nodeList.data(), &NodeList::canRezChanged, essLogAction, [essLogAction] { + { auto nodeList = DependencyManager::get(); + QObject::connect(nodeList.data(), &NodeList::canRezChanged, essLogAction, [essLogAction] { + auto nodeList = DependencyManager::get(); + essLogAction->setEnabled(nodeList->getThisNodeCanRez()); + }); essLogAction->setEnabled(nodeList->getThisNodeCanRez()); - }); - essLogAction->setEnabled(nodeList->getThisNodeCanRez()); + } addActionToQMenuAndActionHash(developerMenu, "Script Log (HMD friendly)...", Qt::NoButton, qApp, SLOT(showScriptLogs())); diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index bb598f0261..bb517f4d60 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -79,7 +79,7 @@ AvatarManager::AvatarManager(QObject* parent) : // when we hear that the user has ignored an avatar by session UUID // immediately remove that avatar instead of waiting for the absence of packets from avatar mixer - connect(nodeList.data(), &NodeList::ignoredNode, this, [=](const QUuid& nodeID, bool enabled) { + connect(nodeList.data(), &NodeList::ignoredNode, this, [this](const QUuid& nodeID, bool enabled) { if (enabled) { removeAvatar(nodeID, KillAvatarReason::AvatarIgnored); } @@ -318,16 +318,21 @@ void AvatarManager::postUpdate(float deltaTime, const render::ScenePointer& scen void AvatarManager::sendIdentityRequest(const QUuid& avatarID) const { auto nodeList = DependencyManager::get(); + QWeakPointer nodeListWeak = nodeList; nodeList->eachMatchingNode( - [&](const SharedNodePointer& node)->bool { - return node->getType() == NodeType::AvatarMixer && node->getActiveSocket(); - }, - [&](const SharedNodePointer& node) { - auto packet = NLPacket::create(PacketType::AvatarIdentityRequest, NUM_BYTES_RFC4122_UUID, true); - packet->write(avatarID.toRfc4122()); - nodeList->sendPacket(std::move(packet), *node); - ++_identityRequestsSent; - }); + [](const SharedNodePointer& node)->bool { + return node->getType() == NodeType::AvatarMixer && node->getActiveSocket(); + }, + [this, avatarID, nodeListWeak](const SharedNodePointer& node) { + auto nodeList = nodeListWeak.lock(); + if (nodeList) { + auto packet = NLPacket::create(PacketType::AvatarIdentityRequest, NUM_BYTES_RFC4122_UUID, true); + packet->write(avatarID.toRfc4122()); + nodeList->sendPacket(std::move(packet), *node); + ++_identityRequestsSent; + } + } + ); } void AvatarManager::simulateAvatarFades(float deltaTime) { diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index de0768b7ad..41855e7973 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -498,14 +498,14 @@ void MyAvatar::update(float deltaTime) { // Get audio loudness data from audio input device // Also get the AudioClient so we can update the avatar bounding box data // on the AudioClient side. - auto audio = DependencyManager::get(); + auto audio = DependencyManager::get().data(); setAudioLoudness(audio->getLastInputLoudness()); setAudioAverageLoudness(audio->getAudioAverageInputLoudness()); glm::vec3 halfBoundingBoxDimensions(_characterController.getCapsuleRadius(), _characterController.getCapsuleHalfHeight(), _characterController.getCapsuleRadius()); // This might not be right! Isn't the capsule local offset in avatar space? -HRS 5/26/17 halfBoundingBoxDimensions += _characterController.getCapsuleLocalOffset(); - QMetaObject::invokeMethod(audio.data(), "setAvatarBoundingBoxParameters", + QMetaObject::invokeMethod(audio, "setAvatarBoundingBoxParameters", Q_ARG(glm::vec3, (getWorldPosition() - halfBoundingBoxDimensions)), Q_ARG(glm::vec3, (halfBoundingBoxDimensions*2.0f))); diff --git a/interface/src/commerce/QmlCommerce.cpp b/interface/src/commerce/QmlCommerce.cpp index 1f44343bdc..1c6600cf3f 100644 --- a/interface/src/commerce/QmlCommerce.cpp +++ b/interface/src/commerce/QmlCommerce.cpp @@ -352,8 +352,7 @@ bool QmlCommerce::openApp(const QString& itemHref) { QJsonObject appFileJsonObject = appFileJsonDocument.object(); QString homeUrl = appFileJsonObject["homeURL"].toString(); - auto tabletScriptingInterface = DependencyManager::get(); - auto tablet = dynamic_cast(tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system")); + auto tablet = dynamic_cast(DependencyManager::get()->getTablet("com.highfidelity.interface.tablet.system")); if (homeUrl.contains(".qml", Qt::CaseInsensitive)) { tablet->loadQMLSource(homeUrl); } else if (homeUrl.contains(".html", Qt::CaseInsensitive)) { diff --git a/interface/src/commerce/Wallet.cpp b/interface/src/commerce/Wallet.cpp index 991f1ebf3f..ef6b4654f5 100644 --- a/interface/src/commerce/Wallet.cpp +++ b/interface/src/commerce/Wallet.cpp @@ -328,7 +328,7 @@ Wallet::Wallet() { packetReceiver.registerListener(PacketType::ChallengeOwnership, this, "handleChallengeOwnershipPacket"); packetReceiver.registerListener(PacketType::ChallengeOwnershipRequest, this, "handleChallengeOwnershipPacket"); - connect(ledger.data(), &Ledger::accountResult, this, [&](QJsonObject result) { + connect(ledger.data(), &Ledger::accountResult, this, [](QJsonObject result) { auto wallet = DependencyManager::get(); auto walletScriptingInterface = DependencyManager::get(); uint status; diff --git a/interface/src/scripting/Audio.cpp b/interface/src/scripting/Audio.cpp index bcb7a6c10f..524170c7a5 100644 --- a/interface/src/scripting/Audio.cpp +++ b/interface/src/scripting/Audio.cpp @@ -60,23 +60,20 @@ Audio::Audio() : _devices(_contextIsHMD) { } bool Audio::startRecording(const QString& filepath) { - auto client = DependencyManager::get().data(); return resultWithWriteLock([&] { - return client->startRecording(filepath); + return DependencyManager::get()->startRecording(filepath); }); } bool Audio::getRecording() { - auto client = DependencyManager::get().data(); return resultWithReadLock([&] { - return client->getRecording(); + return DependencyManager::get()->getRecording(); }); } void Audio::stopRecording() { - auto client = DependencyManager::get().data(); withWriteLock([&] { - client->stopRecording(); + DependencyManager::get()->stopRecording(); }); } diff --git a/interface/src/scripting/AudioDevices.cpp b/interface/src/scripting/AudioDevices.cpp index f08a0bf382..ce82786c8d 100644 --- a/interface/src/scripting/AudioDevices.cpp +++ b/interface/src/scripting/AudioDevices.cpp @@ -360,11 +360,11 @@ void AudioInputDeviceList::onPeakValueListChanged(const QList& peakValueL } AudioDevices::AudioDevices(bool& contextIsHMD) : _contextIsHMD(contextIsHMD) { - auto client = DependencyManager::get(); + auto client = DependencyManager::get().data(); - connect(client.data(), &AudioClient::deviceChanged, this, &AudioDevices::onDeviceChanged, Qt::QueuedConnection); - connect(client.data(), &AudioClient::devicesChanged, this, &AudioDevices::onDevicesChanged, Qt::QueuedConnection); - connect(client.data(), &AudioClient::peakValueListChanged, &_inputs, &AudioInputDeviceList::onPeakValueListChanged, Qt::QueuedConnection); + connect(client, &AudioClient::deviceChanged, this, &AudioDevices::onDeviceChanged, Qt::QueuedConnection); + connect(client, &AudioClient::devicesChanged, this, &AudioDevices::onDevicesChanged, Qt::QueuedConnection); + connect(client, &AudioClient::peakValueListChanged, &_inputs, &AudioInputDeviceList::onPeakValueListChanged, Qt::QueuedConnection); _inputs.onDeviceChanged(client->getActiveAudioDevice(QAudio::AudioInput), contextIsHMD); _outputs.onDeviceChanged(client->getActiveAudioDevice(QAudio::AudioOutput), contextIsHMD); @@ -446,7 +446,7 @@ void AudioDevices::onDevicesChanged(QAudio::Mode mode, const QList(); + auto client = DependencyManager::get().data(); _inputs._hmdSavedDeviceName = getTargetDevice(true, QAudio::AudioInput); _inputs._desktopSavedDeviceName = getTargetDevice(false, QAudio::AudioInput); @@ -494,9 +494,9 @@ void AudioDevices::onDevicesChanged(QAudio::Mode mode, const QList(); + auto client = DependencyManager::get().data(); _requestedInputDevice = device; - QMetaObject::invokeMethod(client.data(), "switchAudioDevice", + QMetaObject::invokeMethod(client, "switchAudioDevice", Q_ARG(QAudio::Mode, QAudio::AudioInput), Q_ARG(const QAudioDeviceInfo&, device)); } else { @@ -511,9 +511,9 @@ void AudioDevices::chooseInputDevice(const QAudioDeviceInfo& device, bool isHMD) void AudioDevices::chooseOutputDevice(const QAudioDeviceInfo& device, bool isHMD) { //check if current context equals device to change if (_contextIsHMD == isHMD) { - auto client = DependencyManager::get(); + auto client = DependencyManager::get().data(); _requestedOutputDevice = device; - QMetaObject::invokeMethod(client.data(), "switchAudioDevice", + QMetaObject::invokeMethod(client, "switchAudioDevice", Q_ARG(QAudio::Mode, QAudio::AudioOutput), Q_ARG(const QAudioDeviceInfo&, device)); } else { diff --git a/interface/src/ui/JSConsole.cpp b/interface/src/ui/JSConsole.cpp index 1ca1ac2842..ed4ee97780 100644 --- a/interface/src/ui/JSConsole.cpp +++ b/interface/src/ui/JSConsole.cpp @@ -312,7 +312,7 @@ JSConsole::~JSConsole() { delete _ui; } -void JSConsole::setScriptEngine(const ScriptEnginePointer& scriptEngine) { +void JSConsole::setScriptEngine(const ScriptEnginePointer& scriptEngine) { if (_scriptEngine == scriptEngine && scriptEngine != nullptr) { return; } diff --git a/interface/src/ui/LoginDialog.cpp b/interface/src/ui/LoginDialog.cpp index 9804c6712a..8a40ee2f83 100644 --- a/interface/src/ui/LoginDialog.cpp +++ b/interface/src/ui/LoginDialog.cpp @@ -162,9 +162,7 @@ void LoginDialog::createAccountFromStream(QString username) { } void LoginDialog::openUrl(const QString& url) const { - - auto tabletScriptingInterface = DependencyManager::get(); - auto tablet = dynamic_cast(tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system")); + auto tablet = dynamic_cast(DependencyManager::get()->getTablet("com.highfidelity.interface.tablet.system")); auto hmd = DependencyManager::get(); auto offscreenUi = DependencyManager::get(); diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp index 682dad74e8..e2037d54d0 100644 --- a/interface/src/ui/PreferencesDialog.cpp +++ b/interface/src/ui/PreferencesDialog.cpp @@ -27,28 +27,27 @@ void setupPreferences() { auto preferences = DependencyManager::get(); - auto nodeList = DependencyManager::get(); auto myAvatar = DependencyManager::get()->getMyAvatar(); static const QString AVATAR_BASICS { "Avatar Basics" }; { - auto getter = [=]()->QString { return myAvatar->getDisplayName(); }; - auto setter = [=](const QString& value) { myAvatar->setDisplayName(value); }; + auto getter = [myAvatar]()->QString { return myAvatar->getDisplayName(); }; + auto setter = [myAvatar](const QString& value) { myAvatar->setDisplayName(value); }; auto preference = new EditPreference(AVATAR_BASICS, "Avatar display name (optional)", getter, setter); preference->setPlaceholderText("Not showing a name"); preferences->addPreference(preference); } { - auto getter = [=]()->QString { return myAvatar->getCollisionSoundURL(); }; - auto setter = [=](const QString& value) { myAvatar->setCollisionSoundURL(value); }; + auto getter = [myAvatar]()->QString { return myAvatar->getCollisionSoundURL(); }; + auto setter = [myAvatar](const QString& value) { myAvatar->setCollisionSoundURL(value); }; auto preference = new EditPreference(AVATAR_BASICS, "Avatar collision sound URL (optional)", getter, setter); preference->setPlaceholderText("Enter the URL of a sound to play when you bump into something"); preferences->addPreference(preference); } { - auto getter = [=]()->QString { return myAvatar->getFullAvatarURLFromPreferences().toString(); }; - auto setter = [=](const QString& value) { myAvatar->useFullAvatarURL(value, ""); qApp->clearAvatarOverrideUrl(); }; + auto getter = [myAvatar]()->QString { return myAvatar->getFullAvatarURLFromPreferences().toString(); }; + auto setter = [myAvatar](const QString& value) { myAvatar->useFullAvatarURL(value, ""); qApp->clearAvatarOverrideUrl(); }; auto preference = new AvatarPreference(AVATAR_BASICS, "Appearance", getter, setter); preferences->addPreference(preference); } @@ -163,8 +162,8 @@ void setupPreferences() { static const QString VIEW_CATEGORY{ "View" }; { - auto getter = [=]()->float { return myAvatar->getRealWorldFieldOfView(); }; - auto setter = [=](float value) { myAvatar->setRealWorldFieldOfView(value); }; + auto getter = [myAvatar]()->float { return myAvatar->getRealWorldFieldOfView(); }; + auto setter = [myAvatar](float value) { myAvatar->setRealWorldFieldOfView(value); }; auto preference = new SpinnerPreference(VIEW_CATEGORY, "Real world vertical field of view (angular size of monitor)", getter, setter); preference->setMin(1); preference->setMax(180); @@ -219,13 +218,13 @@ void setupPreferences() { static const QString AVATAR_TUNING { "Avatar Tuning" }; { - auto getter = [=]()->QString { return myAvatar->getDominantHand(); }; - auto setter = [=](const QString& value) { myAvatar->setDominantHand(value); }; + auto getter = [myAvatar]()->QString { return myAvatar->getDominantHand(); }; + auto setter = [myAvatar](const QString& value) { myAvatar->setDominantHand(value); }; preferences->addPreference(new PrimaryHandPreference(AVATAR_TUNING, "Dominant Hand", getter, setter)); } { - auto getter = [=]()->float { return myAvatar->getTargetScale(); }; - auto setter = [=](float value) { myAvatar->setTargetScale(value); }; + auto getter = [myAvatar]()->float { return myAvatar->getTargetScale(); }; + auto setter = [myAvatar](float value) { myAvatar->setTargetScale(value); }; auto preference = new SpinnerSliderPreference(AVATAR_TUNING, "Avatar Scale", getter, setter); preference->setMin(0.25); preference->setMax(4); @@ -240,16 +239,16 @@ void setupPreferences() { } { - auto getter = [=]()->QString { return myAvatar->getAnimGraphOverrideUrl().toString(); }; - auto setter = [=](const QString& value) { myAvatar->setAnimGraphOverrideUrl(QUrl(value)); }; + auto getter = [myAvatar]()->QString { return myAvatar->getAnimGraphOverrideUrl().toString(); }; + auto setter = [myAvatar](const QString& value) { myAvatar->setAnimGraphOverrideUrl(QUrl(value)); }; auto preference = new EditPreference(AVATAR_TUNING, "Avatar animation JSON", getter, setter); preference->setPlaceholderText("default"); preferences->addPreference(preference); } { - auto getter = [=]()->bool { return myAvatar->getCollisionsEnabled(); }; - auto setter = [=](bool value) { myAvatar->setCollisionsEnabled(value); }; + auto getter = [myAvatar]()->bool { return myAvatar->getCollisionsEnabled(); }; + auto setter = [myAvatar](bool value) { myAvatar->setCollisionsEnabled(value); }; auto preference = new CheckPreference(AVATAR_TUNING, "Enable Avatar collisions", getter, setter); preferences->addPreference(preference); } @@ -270,20 +269,20 @@ void setupPreferences() { { static const QString movementsControlChannel = QStringLiteral("Hifi-Advanced-Movement-Disabler"); - auto getter = [=]()->bool { return myAvatar->useAdvancedMovementControls(); }; - auto setter = [=](bool value) { myAvatar->setUseAdvancedMovementControls(value); }; + auto getter = [myAvatar]()->bool { return myAvatar->useAdvancedMovementControls(); }; + auto setter = [myAvatar](bool value) { myAvatar->setUseAdvancedMovementControls(value); }; preferences->addPreference(new CheckPreference(VR_MOVEMENT, QStringLiteral("Advanced movement for hand controllers"), getter, setter)); } { - auto getter = [=]()->bool { return myAvatar->getFlyingHMDPref(); }; - auto setter = [=](bool value) { myAvatar->setFlyingHMDPref(value); }; + auto getter = [myAvatar]()->bool { return myAvatar->getFlyingHMDPref(); }; + auto setter = [myAvatar](bool value) { myAvatar->setFlyingHMDPref(value); }; preferences->addPreference(new CheckPreference(VR_MOVEMENT, "Flying & jumping (HMD)", getter, setter)); } { - auto getter = [=]()->int { return myAvatar->getSnapTurn() ? 0 : 1; }; - auto setter = [=](int value) { myAvatar->setSnapTurn(value == 0); }; + auto getter = [myAvatar]()->int { return myAvatar->getSnapTurn() ? 0 : 1; }; + auto setter = [myAvatar](int value) { myAvatar->setSnapTurn(value == 0); }; auto preference = new RadioButtonsPreference(VR_MOVEMENT, "Snap turn / Smooth turn", getter, setter); QStringList items; items << "Snap turn" << "Smooth turn"; @@ -309,8 +308,8 @@ void setupPreferences() { static const QString AVATAR_CAMERA{ "Mouse Sensitivity" }; { - auto getter = [=]()->float { return myAvatar->getPitchSpeed(); }; - auto setter = [=](float value) { myAvatar->setPitchSpeed(value); }; + auto getter = [myAvatar]()->float { return myAvatar->getPitchSpeed(); }; + auto setter = [myAvatar](float value) { myAvatar->setPitchSpeed(value); }; auto preference = new SpinnerSliderPreference(AVATAR_CAMERA, "Y input:", getter, setter); preference->setMin(1.0f); preference->setMax(360.0f); @@ -319,8 +318,8 @@ void setupPreferences() { preferences->addPreference(preference); } { - auto getter = [=]()->float { return myAvatar->getYawSpeed(); }; - auto setter = [=](float value) { myAvatar->setYawSpeed(value); }; + auto getter = [myAvatar]()->float { return myAvatar->getYawSpeed(); }; + auto setter = [myAvatar](float value) { myAvatar->setYawSpeed(value); }; auto preference = new SpinnerSliderPreference(AVATAR_CAMERA, "X input:", getter, setter); preference->setMin(1.0f); preference->setMax(360.0f); @@ -381,12 +380,24 @@ void setupPreferences() { { static const QString NETWORKING("Networking"); - auto nodelist = DependencyManager::get(); + QWeakPointer nodeListWeak = DependencyManager::get(); { static const int MIN_PORT_NUMBER { 0 }; static const int MAX_PORT_NUMBER { 65535 }; - auto getter = [nodelist] { return static_cast(nodelist->getSocketLocalPort()); }; - auto setter = [nodelist](int preset) { nodelist->setSocketLocalPort(static_cast(preset)); }; + auto getter = [nodeListWeak] { + auto nodeList = nodeListWeak.lock(); + if (nodeList) { + return static_cast(nodeList->getSocketLocalPort()); + } else { + return -1; + } + }; + auto setter = [nodeListWeak](int preset) { + auto nodeList = nodeListWeak.lock(); + if (nodeList) { + nodeList->setSocketLocalPort(static_cast(preset)); + } + }; auto preference = new IntSpinnerPreference(NETWORKING, "Listening Port", getter, setter); preference->setMin(MIN_PORT_NUMBER); preference->setMax(MAX_PORT_NUMBER); diff --git a/interface/src/ui/Stats.cpp b/interface/src/ui/Stats.cpp index 43768d90d2..ce1cd51de1 100644 --- a/interface/src/ui/Stats.cpp +++ b/interface/src/ui/Stats.cpp @@ -174,7 +174,7 @@ void Stats::updateStats(bool force) { int octreeServerCount = 0; int pingOctreeMax = 0; int totalEntityKbps = 0; - nodeList->eachNode([&](const SharedNodePointer& node) { + nodeList->eachNode([&totalPingOctree, &totalEntityKbps, &octreeServerCount, &pingOctreeMax](const SharedNodePointer& node) { // TODO: this should also support entities if (node->getType() == NodeType::EntityServer) { totalPingOctree += node->getPingMs(); @@ -219,7 +219,7 @@ void Stats::updateStats(bool force) { STAT_UPDATE_FLOAT(myAvatarSendRate, avatarManager->getMyAvatarSendRate(), 0.1f); SharedNodePointer audioMixerNode = nodeList->soloNodeOfType(NodeType::AudioMixer); - auto audioClient = DependencyManager::get(); + auto audioClient = DependencyManager::get().data(); if (audioMixerNode || force) { STAT_UPDATE(audioMixerKbps, (int)roundf( bandwidthRecorder->getAverageInputKilobitsPerSecond(NodeType::AudioMixer) + diff --git a/interface/src/ui/TestingDialog.cpp b/interface/src/ui/TestingDialog.cpp index 6143f20ee6..5f0b20ca7e 100644 --- a/interface/src/ui/TestingDialog.cpp +++ b/interface/src/ui/TestingDialog.cpp @@ -23,8 +23,7 @@ TestingDialog::TestingDialog(QWidget* parent) : _console->setFixedHeight(TESTING_CONSOLE_HEIGHT); - auto _engines = DependencyManager::get(); - _engine = _engines->loadScript(qApp->applicationDirPath() + testRunnerRelativePath); + _engine = DependencyManager::get()->loadScript(qApp->applicationDirPath() + testRunnerRelativePath); _console->setScriptEngine(_engine); connect(_engine.data(), &ScriptEngine::finished, this, &TestingDialog::onTestingFinished); } diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp index 6ac30e7f73..6a9363f309 100644 --- a/libraries/audio-client/src/AudioClient.cpp +++ b/libraries/audio-client/src/AudioClient.cpp @@ -274,31 +274,14 @@ AudioClient::~AudioClient() { } void AudioClient::customDeleter() { - deleteLater(); -} - -void AudioClient::cleanupBeforeQuit() { - // FIXME: this should be put in customDeleter, but there is still a reference to this when it is called, - // so this must be explicitly, synchronously stopped - static ConditionalGuard guard; - if (QThread::currentThread() != thread()) { - // This will likely be called from the main thread, but we don't want to do blocking queued calls - // from the main thread, so we use a normal auto-connection invoke, and then use a conditional to wait - // for completion - // The effect is the same, yes, but we actually want to avoid the use of Qt::BlockingQueuedConnection - // in the code - QMetaObject::invokeMethod(this, "cleanupBeforeQuit"); - guard.wait(); - return; - } - #if defined(Q_OS_ANDROID) _shouldRestartInputSetup = false; #endif stop(); _checkDevicesTimer->stop(); _checkPeakValuesTimer->stop(); - guard.trigger(); + + deleteLater(); } void AudioClient::handleMismatchAudioFormat(SharedNodePointer node, const QString& currentCodec, const QString& recievedCodec) { diff --git a/libraries/audio-client/src/AudioClient.h b/libraries/audio-client/src/AudioClient.h index 9ee7bcfeba..8599c990a3 100644 --- a/libraries/audio-client/src/AudioClient.h +++ b/libraries/audio-client/src/AudioClient.h @@ -171,7 +171,6 @@ public: public slots: void start(); void stop(); - void cleanupBeforeQuit(); void handleAudioEnvironmentDataPacket(QSharedPointer message); void handleAudioDataPacket(QSharedPointer message); diff --git a/libraries/audio-client/src/AudioIOStats.cpp b/libraries/audio-client/src/AudioIOStats.cpp index 1717ad1f9c..1e45622fdc 100644 --- a/libraries/audio-client/src/AudioIOStats.cpp +++ b/libraries/audio-client/src/AudioIOStats.cpp @@ -95,8 +95,6 @@ void AudioIOStats::processStreamStatsPacket(QSharedPointer mess } void AudioIOStats::publish() { - auto audioIO = DependencyManager::get(); - // call _receivedAudioStream's per-second callback _receivedAudioStream->perSecondCallbackForUpdatingStats(); diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index a2006d3503..62c7a7053f 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -2069,7 +2069,7 @@ void AvatarData::sendIdentityPacket() { auto packetList = NLPacketList::create(PacketType::AvatarIdentity, QByteArray(), true, true); packetList->write(identityData); nodeList->eachMatchingNode( - [&](const SharedNodePointer& node)->bool { + [](const SharedNodePointer& node)->bool { return node->getType() == NodeType::AvatarMixer && node->getActiveSocket(); }, [&](const SharedNodePointer& node) { diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index ff636f0877..c080fbbb88 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -1252,7 +1252,7 @@ bool EntityScriptingInterface::actionWorker(const QUuid& entityID, EntityItemPointer entity; bool doTransmit = false; - _entityTree->withWriteLock([&] { + _entityTree->withWriteLock([this, &entity, entityID, myNodeID, &doTransmit, actor, &properties] { EntitySimulationPointer simulation = _entityTree->getSimulation(); entity = _entityTree->findEntityByEntityItemID(entityID); if (!entity) { diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 66dd6adfb5..377e192bb1 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -1435,7 +1435,7 @@ void EntityTree::validatePop(const QString& certID, const EntityItemID& entityIt QNetworkReply* networkReply = networkAccessManager.put(networkRequest, QJsonDocument(request).toJson()); - connect(networkReply, &QNetworkReply::finished, [=]() { + connect(networkReply, &QNetworkReply::finished, [this, networkReply, entityItemID, certID, senderNode]() { QJsonObject jsonObject = QJsonDocument::fromJson(networkReply->readAll()).object(); jsonObject = jsonObject["data"].toObject(); diff --git a/libraries/script-engine/src/ScriptEngines.cpp b/libraries/script-engine/src/ScriptEngines.cpp index d385dcca84..6393ff33ea 100644 --- a/libraries/script-engine/src/ScriptEngines.cpp +++ b/libraries/script-engine/src/ScriptEngines.cpp @@ -133,7 +133,7 @@ QUrl expandScriptUrl(const QUrl& rawScriptURL) { QObject* scriptsModel(); bool NativeScriptInitializers::registerNativeScriptInitializer(NativeScriptInitializer initializer) { - return registerScriptInitializer([=](ScriptEnginePointer engine) { + return registerScriptInitializer([initializer](ScriptEnginePointer engine) { initializer(qobject_cast(engine.data())); }); } @@ -492,8 +492,7 @@ ScriptEnginePointer ScriptEngines::loadScript(const QUrl& scriptFilename, bool i return scriptEngine; } - scriptEngine = ScriptEnginePointer(new ScriptEngine(_context, NO_SCRIPT, "about:" + scriptFilename.fileName())); - addScriptEngine(scriptEngine); + scriptEngine = scriptEngineFactory(_context, NO_SCRIPT, "about:" + scriptFilename.fileName()); scriptEngine->setUserLoaded(isUserLoaded); scriptEngine->setQuitWhenFinished(quitWhenFinished); @@ -564,10 +563,10 @@ int ScriptEngines::runScriptInitializers(ScriptEnginePointer scriptEngine) { void ScriptEngines::launchScriptEngine(ScriptEnginePointer scriptEngine) { connect(scriptEngine.data(), &ScriptEngine::finished, this, &ScriptEngines::onScriptFinished, Qt::DirectConnection); - connect(scriptEngine.data(), &ScriptEngine::loadScript, [&](const QString& scriptName, bool userLoaded) { + connect(scriptEngine.data(), &ScriptEngine::loadScript, [this](const QString& scriptName, bool userLoaded) { loadScript(scriptName, userLoaded); }); - connect(scriptEngine.data(), &ScriptEngine::reloadScript, [&](const QString& scriptName, bool userLoaded) { + connect(scriptEngine.data(), &ScriptEngine::reloadScript, [this](const QString& scriptName, bool userLoaded) { loadScript(scriptName, userLoaded, false, false, true); }); diff --git a/libraries/shared/src/DependencyManager.h b/libraries/shared/src/DependencyManager.h index e6fc7ce96b..da877f7b3b 100644 --- a/libraries/shared/src/DependencyManager.h +++ b/libraries/shared/src/DependencyManager.h @@ -139,7 +139,13 @@ QSharedPointer DependencyManager::set(Args&&... args) { template void DependencyManager::destroy() { static size_t hashCode = manager().getHashCode(); - manager().safeGet(hashCode).clear(); + QSharedPointer& shared = manager().safeGet(hashCode); + QWeakPointer weak = shared; + shared.clear(); + // Check that the dependency was actually destroyed. If it wasn't, it was improperly captured somewhere + if (weak.lock()) { + qWarning() << "DependencyManager::destroy():" << typeid(T).name() << "was not properly destroyed!"; + } } template diff --git a/libraries/ui/src/ui/OffscreenQmlSurface.cpp b/libraries/ui/src/ui/OffscreenQmlSurface.cpp index e7f307aa4f..74098f69c7 100644 --- a/libraries/ui/src/ui/OffscreenQmlSurface.cpp +++ b/libraries/ui/src/ui/OffscreenQmlSurface.cpp @@ -329,8 +329,7 @@ void OffscreenQmlSurface::onRootCreated() { getSurfaceContext()->setContextProperty("offscreenWindow", QVariant::fromValue(getWindow())); // Connect with the audio client and listen for audio device changes - auto audioIO = DependencyManager::get(); - connect(audioIO.data(), &AudioClient::deviceChanged, this, [&](QAudio::Mode mode, const QAudioDeviceInfo& device) { + connect(DependencyManager::get().data(), &AudioClient::deviceChanged, this, [this](QAudio::Mode mode, const QAudioDeviceInfo& device) { if (mode == QAudio::Mode::AudioOutput) { QMetaObject::invokeMethod(this, "changeAudioOutputDevice", Qt::QueuedConnection, Q_ARG(QString, device.deviceName())); }