From 24178b72fb8c854305f524ef694810e9625a8073 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Tue, 21 Apr 2015 21:55:52 -0700 Subject: [PATCH 01/13] Use lobby.js as starting point for avatarSelector.js --- examples/avatarSelector.js | 400 +++++++++++++++++++++++++++++++++++++ 1 file changed, 400 insertions(+) create mode 100644 examples/avatarSelector.js diff --git a/examples/avatarSelector.js b/examples/avatarSelector.js new file mode 100644 index 0000000000..41d6abbe2b --- /dev/null +++ b/examples/avatarSelector.js @@ -0,0 +1,400 @@ +// +// avatarSelector.js +// examples +// +// Created by David Rowe on 21 Apr 2015. +// Copyright 2015 High Fidelity, Inc. +// +// Based on lobby.js created by Stephen Birarda on 17 Oct 2014. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/"; + +var panelWall = false; +var orbShell = false; +var descriptionText = false; +var showText = false; + +// used for formating the description text, in meters +var textWidth = 4; +var textHeight = .5; +var numberOfLines = 2; +var textMargin = 0.0625; +var lineHeight = (textHeight - (2 * textMargin)) / numberOfLines; + +var avatarStickPosition = {}; + +var orbNaturalExtentsMin = { x: -1.230354, y: -1.22077, z: -1.210487 }; +var orbNaturalExtentsMax = { x: 1.230353, y: 1.229819, z: 1.210487 }; +var panelsNaturalExtentsMin = { x: -1.223182, y: -0.348487, z: 0.0451369 }; +var panelsNaturalExtentsMax = { x: 1.223039, y: 0.602978, z: 1.224298 }; + +var orbNaturalDimensions = Vec3.subtract(orbNaturalExtentsMax, orbNaturalExtentsMin); +var panelsNaturalDimensions = Vec3.subtract(panelsNaturalExtentsMax, panelsNaturalExtentsMin); + +var SCALING_FACTOR = 10; +var orbDimensions = Vec3.multiply(orbNaturalDimensions, SCALING_FACTOR); +var panelsDimensions = Vec3.multiply(panelsNaturalDimensions, SCALING_FACTOR); + +var orbNaturalCenter = Vec3.sum(orbNaturalExtentsMin, Vec3.multiply(orbNaturalDimensions, 0.5)); +var panelsNaturalCenter = Vec3.sum(panelsNaturalExtentsMin, Vec3.multiply(panelsNaturalDimensions, 0.5)); +var orbCenter = Vec3.multiply(orbNaturalCenter, SCALING_FACTOR); +var panelsCenter = Vec3.multiply(panelsNaturalCenter, SCALING_FACTOR); +var panelsCenterShift = Vec3.subtract(panelsCenter, orbCenter); + +var ORB_SHIFT = { x: 0, y: -1.4, z: -0.8 }; + +var LOBBY_PANEL_WALL_URL = HIFI_PUBLIC_BUCKET + "models/sets/Lobby/PanelWallForInterface.fbx"; +var LOBBY_BLANK_PANEL_TEXTURE_URL = HIFI_PUBLIC_BUCKET + "models/sets/Lobby/Texture.jpg"; +var LOBBY_SHELL_URL = HIFI_PUBLIC_BUCKET + "models/sets/Lobby/LobbyShellForInterface.fbx"; + +var droneSound = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Lobby/drone.stereo.raw") +var currentDrone = null; + +var latinSound = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Lobby/latin.stereo.raw") +var latinInjector = null; +var elevatorSound = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Lobby/elevator.stereo.raw") +var elevatorInjector = null; +var currentMuzakInjector = null; +var currentSound = null; + +function textOverlayPosition() { + var TEXT_DISTANCE_OUT = 6; + var TEXT_DISTANCE_DOWN = -2; + return Vec3.sum(Vec3.sum(Camera.position, Vec3.multiply(Quat.getFront(Camera.orientation), TEXT_DISTANCE_OUT)), + Vec3.multiply(Quat.getUp(Camera.orientation), TEXT_DISTANCE_DOWN)); +} + +var panelPlaceOrder = [ + 7, 8, 9, 10, 11, 12, 13, + 0, 1, 2, 3, 4, 5, 6, + 14, 15, 16, 17, 18, 19, 20 +]; + +// place index is 0-based +function placeIndexToPanelIndex(placeIndex) { + return panelPlaceOrder.indexOf(placeIndex) + 1; +} + +// Panel index is 1-based +function panelIndexToPlaceIndex(panelIndex) { + return panelPlaceOrder[panelIndex - 1]; +} + +var MAX_NUM_PANELS = 21; +var DRONE_VOLUME = 0.3; + +function drawLobby() { + if (!panelWall) { + print("Adding overlays for the lobby panel wall and orb shell."); + + var cameraEuler = Quat.safeEulerAngles(Camera.orientation); + var towardsMe = Quat.angleAxis(cameraEuler.y + 180, { x: 0, y: 1, z: 0 }); + + var orbPosition = Vec3.sum(Camera.position, Vec3.multiplyQbyV(towardsMe, ORB_SHIFT)); + + var panelWallProps = { + url: LOBBY_PANEL_WALL_URL, + position: Vec3.sum(orbPosition, Vec3.multiplyQbyV(towardsMe, panelsCenterShift)), + rotation: towardsMe, + dimensions: panelsDimensions + }; + + var orbShellProps = { + url: LOBBY_SHELL_URL, + position: orbPosition, + rotation: towardsMe, + dimensions: orbDimensions, + ignoreRayIntersection: true + }; + + var windowDimensions = Controller.getViewportDimensions(); + + var descriptionTextProps = { + position: textOverlayPosition(), + dimensions: { x: textWidth, y: textHeight }, + backgroundColor: { red: 0, green: 0, blue: 0 }, + color: { red: 255, green: 255, blue: 255 }, + topMargin: textMargin, + leftMargin: textMargin, + bottomMargin: textMargin, + rightMargin: textMargin, + text: "", + lineHeight: lineHeight, + alpha: 0.9, + backgroundAlpha: 0.9, + ignoreRayIntersection: true, + visible: false, + isFacingAvatar: true + }; + + avatarStickPosition = MyAvatar.position; + + panelWall = Overlays.addOverlay("model", panelWallProps); + orbShell = Overlays.addOverlay("model", orbShellProps); + descriptionText = Overlays.addOverlay("text3d", descriptionTextProps); + + if (droneSound.downloaded) { + // start the drone sound + if (!currentDrone) { + currentDrone = Audio.playSound(droneSound, { stereo: true, loop: true, localOnly: true, volume: DRONE_VOLUME }); + } else { + currentDrone.restart(); + } + } + + // start one of our muzak sounds + playRandomMuzak(); + } +} + +var places = {}; + +function changeLobbyTextures() { + var req = new XMLHttpRequest(); + req.open("GET", "https://metaverse.highfidelity.com/api/v1/places?limit=21", false); + req.send(); + + places = JSON.parse(req.responseText).data.places; + + var NUM_PANELS = places.length; + + var textureProp = { + textures: {} + }; + + for (var j = 0; j < NUM_PANELS; j++) { + var panelIndex = placeIndexToPanelIndex(j); + textureProp["textures"]["file" + panelIndex] = places[j].previews.lobby; + }; + + Overlays.editOverlay(panelWall, textureProp); +} + +var MUZAK_VOLUME = 0.1; + +function playCurrentSound(secondOffset) { + if (currentSound == latinSound) { + if (!latinInjector) { + latinInjector = Audio.playSound(latinSound, { localOnly: true, secondOffset: secondOffset, volume: MUZAK_VOLUME }); + } else { + latinInjector.restart(); + } + + currentMuzakInjector = latinInjector; + } else if (currentSound == elevatorSound) { + if (!elevatorInjector) { + elevatorInjector = Audio.playSound(elevatorSound, { localOnly: true, secondOffset: secondOffset, volume: MUZAK_VOLUME }); + } else { + elevatorInjector.restart(); + } + + currentMuzakInjector = elevatorInjector; + } +} + +function playNextMuzak() { + if (panelWall) { + if (currentSound == latinSound) { + if (elevatorSound.downloaded) { + currentSound = elevatorSound; + } + } else if (currentSound == elevatorSound) { + if (latinSound.downloaded) { + currentSound = latinSound; + } + } + + playCurrentSound(0); + } +} + +function playRandomMuzak() { + currentSound = null; + + if (latinSound.downloaded && elevatorSound.downloaded) { + currentSound = Math.random() < 0.5 ? latinSound : elevatorSound; + } else if (latinSound.downloaded) { + currentSound = latinSound; + } else if (elevatorSound.downloaded) { + currentSound = elevatorSound; + } + + if (currentSound) { + // pick a random number of seconds from 0-10 to offset the muzak + var secondOffset = Math.random() * 10; + + playCurrentSound(secondOffset); + } else { + currentMuzakInjector = null; + } +} + +function cleanupLobby() { + toggleEnvironmentRendering(true); + + // for each of the 21 placeholder textures, set them back to default so the cached model doesn't have changed textures + var panelTexturesReset = {}; + panelTexturesReset["textures"] = {}; + + for (var j = 0; j < MAX_NUM_PANELS; j++) { + panelTexturesReset["textures"]["file" + (j + 1)] = LOBBY_BLANK_PANEL_TEXTURE_URL; + }; + + Overlays.editOverlay(panelWall, panelTexturesReset); + + Overlays.deleteOverlay(panelWall); + Overlays.deleteOverlay(orbShell); + Overlays.deleteOverlay(descriptionText); + + panelWall = false; + orbShell = false; + + if (currentDrone) { + currentDrone.stop(); + currentDrone = null + } + + if (currentMuzakInjector) { + currentMuzakInjector.stop(); + currentMuzakInjector = null; + } + + places = {}; + +} + +function actionStartEvent(event) { + if (panelWall) { + // we've got an action event and our panel wall is up + // check if we hit a panel and if we should jump there + var result = Overlays.findRayIntersection(event.actionRay); + if (result.intersects && result.overlayID == panelWall) { + + var panelName = result.extraInfo; + + var panelStringIndex = panelName.indexOf("Panel"); + if (panelStringIndex != -1) { + var panelIndex = parseInt(panelName.slice(5)); + var placeIndex = panelIndexToPlaceIndex(panelIndex); + if (placeIndex < places.length) { + var actionPlace = places[placeIndex]; + + print("Jumping to " + actionPlace.name + " at " + actionPlace.address + + " after click on panel " + panelIndex + " with place index " + placeIndex); + + Window.location = actionPlace.address; + maybeCleanupLobby(); + } + } + } + } +} + +function backStartEvent() { + if (!panelWall) { + toggleEnvironmentRendering(false); + drawLobby(); + changeLobbyTextures(); + } else { + cleanupLobby(); + } +} + +var CLEANUP_EPSILON_DISTANCE = 0.05; + +function maybeCleanupLobby() { + if (panelWall && Vec3.length(Vec3.subtract(avatarStickPosition, MyAvatar.position)) > CLEANUP_EPSILON_DISTANCE) { + cleanupLobby(); + } +} + +function toggleEnvironmentRendering(shouldRender) { + Scene.shouldRenderAvatars = shouldRender; + Scene.shouldRenderEntities = shouldRender; +} + +function handleLookAt(pickRay) { + if (panelWall && descriptionText) { + // we've got an action event and our panel wall is up + // check if we hit a panel and if we should jump there + var result = Overlays.findRayIntersection(pickRay); + if (result.intersects && result.overlayID == panelWall) { + var panelName = result.extraInfo; + var panelStringIndex = panelName.indexOf("Panel"); + if (panelStringIndex != -1) { + var panelIndex = parseInt(panelName.slice(5)); + var placeIndex = panelIndexToPlaceIndex(panelIndex); + if (placeIndex < places.length) { + var actionPlace = places[placeIndex]; + + if (actionPlace.description == "") { + Overlays.editOverlay(descriptionText, { text: actionPlace.name, visible: showText }); + } else { + // handle line wrapping + var allWords = actionPlace.description.split(" "); + var currentGoodLine = ""; + var currentTestLine = ""; + var formatedDescription = ""; + var wordsFormated = 0; + var currentTestWord = 0; + var wordsOnLine = 0; + while (wordsFormated < allWords.length) { + // first add the "next word" to the line and test it. + currentTestLine = currentGoodLine; + if (wordsOnLine > 0) { + currentTestLine += " " + allWords[currentTestWord]; + } else { + currentTestLine = allWords[currentTestWord]; + } + var lineLength = Overlays.textSize(descriptionText, currentTestLine).width; + if (lineLength < textWidth || wordsOnLine == 0) { + wordsFormated++; + currentTestWord++; + wordsOnLine++; + currentGoodLine = currentTestLine; + } else { + formatedDescription += currentGoodLine + "\n"; + wordsOnLine = 0; + currentGoodLine = ""; + currentTestLine = ""; + } + } + formatedDescription += currentGoodLine; + Overlays.editOverlay(descriptionText, { text: formatedDescription, visible: showText }); + } + } else { + Overlays.editOverlay(descriptionText, { text: "", visible: false }); + } + } + } + } +} + +function update(deltaTime) { + maybeCleanupLobby(); + if (panelWall) { + Overlays.editOverlay(descriptionText, { position: textOverlayPosition() }); + + // if the reticle is up then we may need to play the next muzak + if (currentMuzakInjector && !currentMuzakInjector.isPlaying) { + playNextMuzak(); + } + } +} + +function mouseMoveEvent(event) { + if (panelWall) { + var pickRay = Camera.computePickRay(event.x, event.y); + handleLookAt(pickRay); + } +} + +Controller.actionStartEvent.connect(actionStartEvent); +Controller.backStartEvent.connect(backStartEvent); +Script.update.connect(update); +Script.scriptEnding.connect(maybeCleanupLobby); +Controller.mouseMoveEvent.connect(mouseMoveEvent); From 63d0efcdecf7da71746163c304fd7a1b58d05316 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Wed, 22 Apr 2015 09:16:15 -0700 Subject: [PATCH 02/13] Open and close avatar selector with Ctrl-A --- examples/avatarSelector.js | 33 ++++++++++++++++++++++++--------- interface/src/Application.cpp | 2 +- 2 files changed, 25 insertions(+), 10 deletions(-) diff --git a/examples/avatarSelector.js b/examples/avatarSelector.js index 41d6abbe2b..dfc3f21cb5 100644 --- a/examples/avatarSelector.js +++ b/examples/avatarSelector.js @@ -89,7 +89,7 @@ var DRONE_VOLUME = 0.3; function drawLobby() { if (!panelWall) { - print("Adding overlays for the lobby panel wall and orb shell."); + print("Adding overlays for the avatar selector panel wall and orb shell."); var cameraEuler = Quat.safeEulerAngles(Camera.orientation); var towardsMe = Quat.angleAxis(cameraEuler.y + 180, { x: 0, y: 1, z: 0 }); @@ -294,13 +294,27 @@ function actionStartEvent(event) { } } -function backStartEvent() { - if (!panelWall) { - toggleEnvironmentRendering(false); - drawLobby(); - changeLobbyTextures(); - } else { - cleanupLobby(); +var control = false; + +function keyPressEvent(event) { + if (event.text === "CONTROL") { + control = true; + } + + if (control && event.text === "a") { + if (!panelWall) { + toggleEnvironmentRendering(false); + drawLobby(); + changeLobbyTextures(); + } else { + cleanupLobby(); + } + } +} + +function keyReleaseEvent(event) { + if (event.text === "CONTROL") { + control = false; } } @@ -394,7 +408,8 @@ function mouseMoveEvent(event) { } Controller.actionStartEvent.connect(actionStartEvent); -Controller.backStartEvent.connect(backStartEvent); +Controller.keyPressEvent.connect(keyPressEvent); +Controller.keyReleaseEvent.connect(keyReleaseEvent); Script.update.connect(update); Script.scriptEnding.connect(maybeCleanupLobby); Controller.mouseMoveEvent.connect(mouseMoveEvent); diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 34825ee725..734738a290 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1020,7 +1020,7 @@ void Application::keyPressEvent(QKeyEvent* event) { case Qt::Key_A: if (isShifted) { Menu::getInstance()->triggerOption(MenuOption::Atmosphere); - } else { + } else if (!isMeta) { _myAvatar->setDriveKeys(ROT_LEFT, 1.0f); } break; From 2eb50596683fffa58842a2d5b80ae4718b1fe1f8 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Wed, 22 Apr 2015 10:59:53 -0700 Subject: [PATCH 03/13] Display avatar images and change avatar upon selection --- examples/avatarSelector.js | 41 +++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/examples/avatarSelector.js b/examples/avatarSelector.js index dfc3f21cb5..dc2916a1a8 100644 --- a/examples/avatarSelector.js +++ b/examples/avatarSelector.js @@ -74,9 +74,9 @@ var panelPlaceOrder = [ 14, 15, 16, 17, 18, 19, 20 ]; -// place index is 0-based -function placeIndexToPanelIndex(placeIndex) { - return panelPlaceOrder.indexOf(placeIndex) + 1; +// Avatar index is 0-based +function avatarIndexToPanelIndex(avatarIndex) { + return panelPlaceOrder.indexOf(avatarIndex) + 1; } // Panel index is 1-based @@ -151,24 +151,24 @@ function drawLobby() { } } -var places = {}; +var avatars = {}; function changeLobbyTextures() { var req = new XMLHttpRequest(); - req.open("GET", "https://metaverse.highfidelity.com/api/v1/places?limit=21", false); - req.send(); + req.open("GET", "https://metaverse.highfidelity.com/api/v1/marketplace?category=head+%26+body&limit=21", false); + req.send(); // Data returned is randomized. - places = JSON.parse(req.responseText).data.places; + avatars = JSON.parse(req.responseText).data.items; - var NUM_PANELS = places.length; + var NUM_PANELS = avatars.length; var textureProp = { textures: {} }; for (var j = 0; j < NUM_PANELS; j++) { - var panelIndex = placeIndexToPanelIndex(j); - textureProp["textures"]["file" + panelIndex] = places[j].previews.lobby; + var panelIndex = avatarIndexToPanelIndex(j); + textureProp["textures"]["file" + panelIndex] = avatars[j].preview_url; }; Overlays.editOverlay(panelWall, textureProp); @@ -263,7 +263,7 @@ function cleanupLobby() { currentMuzakInjector = null; } - places = {}; + avatars = {}; } @@ -279,14 +279,15 @@ function actionStartEvent(event) { var panelStringIndex = panelName.indexOf("Panel"); if (panelStringIndex != -1) { var panelIndex = parseInt(panelName.slice(5)); - var placeIndex = panelIndexToPlaceIndex(panelIndex); - if (placeIndex < places.length) { - var actionPlace = places[placeIndex]; + var avatarIndex = panelIndexToPlaceIndex(panelIndex); + if (avatarIndex < avatars.length) { + var actionPlace = avatars[avatarIndex]; - print("Jumping to " + actionPlace.name + " at " + actionPlace.address - + " after click on panel " + panelIndex + " with place index " + placeIndex); + print("Changing avatar to " + actionPlace.name + + " after click on panel " + panelIndex + " with avatar index " + avatarIndex); + + MyAvatar.useFullAvatarURL(actionPlace.content_url); - Window.location = actionPlace.address; maybeCleanupLobby(); } } @@ -341,9 +342,9 @@ function handleLookAt(pickRay) { var panelStringIndex = panelName.indexOf("Panel"); if (panelStringIndex != -1) { var panelIndex = parseInt(panelName.slice(5)); - var placeIndex = panelIndexToPlaceIndex(panelIndex); - if (placeIndex < places.length) { - var actionPlace = places[placeIndex]; + var avatarIndex = panelIndexToPlaceIndex(panelIndex); + if (avatarIndex < avatars.length) { + var actionPlace = avatars[avatarIndex]; if (actionPlace.description == "") { Overlays.editOverlay(descriptionText, { text: actionPlace.name, visible: showText }); From 02fd9987c7a6d340e0f5b207b3a07499974529df Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 28 Apr 2015 18:38:41 -0700 Subject: [PATCH 04/13] rework audio mixer so it can exit cleanly --- assignment-client/src/AssignmentClient.cpp | 12 +- assignment-client/src/AssignmentClient.h | 3 + assignment-client/src/AssignmentClientApp.cpp | 6 + .../src/AssignmentClientMonitor.cpp | 6 + .../src/AssignmentClientMonitor.h | 3 + assignment-client/src/audio/AudioMixer.cpp | 159 ++++++++++-------- assignment-client/src/audio/AudioMixer.h | 10 ++ libraries/networking/src/LimitedNodeList.h | 4 + .../networking/src/ThreadedAssignment.cpp | 23 ++- libraries/networking/src/ThreadedAssignment.h | 10 ++ 10 files changed, 155 insertions(+), 81 deletions(-) diff --git a/assignment-client/src/AssignmentClient.cpp b/assignment-client/src/AssignmentClient.cpp index a0da273462..5a6868e7e4 100644 --- a/assignment-client/src/AssignmentClient.cpp +++ b/assignment-client/src/AssignmentClient.cpp @@ -114,7 +114,16 @@ void AssignmentClient::stopAssignmentClient() { qDebug() << "Exiting."; _requestTimer.stop(); _statsTimerACM.stop(); - QCoreApplication::quit(); + if (_currentAssignment) { + _currentAssignment->aboutToQuit(); + // _currentAssignment->aboutToFinish(); + _currentAssignment->thread()->wait(); + } +} + + +void AssignmentClient::aboutToQuit() { + stopAssignmentClient(); } @@ -197,6 +206,7 @@ void AssignmentClient::readPendingDatagrams() { // start the deployed assignment AssignmentThread* workerThread = new AssignmentThread(_currentAssignment, this); + workerThread->setObjectName("worker"); connect(workerThread, &QThread::started, _currentAssignment.data(), &ThreadedAssignment::run); connect(_currentAssignment.data(), &ThreadedAssignment::finished, workerThread, &QThread::quit); diff --git a/assignment-client/src/AssignmentClient.h b/assignment-client/src/AssignmentClient.h index 08673ab04c..1ffb862dd3 100644 --- a/assignment-client/src/AssignmentClient.h +++ b/assignment-client/src/AssignmentClient.h @@ -34,6 +34,9 @@ private slots: void sendStatsPacketToACM(); void stopAssignmentClient(); +public slots: + void aboutToQuit(); + private: void setUpStatsToMonitor(int ppid); Assignment _requestAssignment; diff --git a/assignment-client/src/AssignmentClientApp.cpp b/assignment-client/src/AssignmentClientApp.cpp index 17f2eac70d..2fcbd67be1 100644 --- a/assignment-client/src/AssignmentClientApp.cpp +++ b/assignment-client/src/AssignmentClientApp.cpp @@ -10,6 +10,7 @@ // #include +#include #include #include @@ -180,14 +181,19 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) : } } + QThread::currentThread()->setObjectName("main thread"); if (numForks || minForks || maxForks) { AssignmentClientMonitor monitor(numForks, minForks, maxForks, requestAssignmentType, assignmentPool, walletUUID, assignmentServerHostname, assignmentServerPort); + connect(this, &QCoreApplication::aboutToQuit, &monitor, &AssignmentClientMonitor::aboutToQuit); + + exec(); } else { AssignmentClient client(ppid, requestAssignmentType, assignmentPool, walletUUID, assignmentServerHostname, assignmentServerPort); + connect(this, &QCoreApplication::aboutToQuit, &client, &AssignmentClient::aboutToQuit); exec(); } } diff --git a/assignment-client/src/AssignmentClientMonitor.cpp b/assignment-client/src/AssignmentClientMonitor.cpp index d591087acd..14eb93ad6e 100644 --- a/assignment-client/src/AssignmentClientMonitor.cpp +++ b/assignment-client/src/AssignmentClientMonitor.cpp @@ -80,6 +80,12 @@ void AssignmentClientMonitor::stopChildProcesses() { }); } + +void AssignmentClientMonitor::aboutToQuit() { + stopChildProcesses(); +} + + void AssignmentClientMonitor::spawnChildClient() { QProcess *assignmentClient = new QProcess(this); diff --git a/assignment-client/src/AssignmentClientMonitor.h b/assignment-client/src/AssignmentClientMonitor.h index 996220b1b4..23f50ef67d 100644 --- a/assignment-client/src/AssignmentClientMonitor.h +++ b/assignment-client/src/AssignmentClientMonitor.h @@ -38,6 +38,9 @@ private slots: void readPendingDatagrams(); void checkSpares(); +public slots: + void aboutToQuit(); + private: void spawnChildClient(); QTimer _checkSparesTimer; // every few seconds see if it need fewer or more spare children diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 06e6f77f69..5d7601ba55 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -588,7 +588,6 @@ void AudioMixer::sendStatsPacket() { _sumMixes = 0; _numStatFrames = 0; - // NOTE: These stats can be too large to fit in an MTU, so we break it up into multiple packts... QJsonObject statsObject2; @@ -712,78 +711,90 @@ void AudioMixer::run() { // check the settings object to see if we have anything we can parse out parseSettingsObject(settingsObject); - int nextFrame = 0; - QElapsedTimer timer; - timer.start(); + _nextFrame = 0; + _timer.start(); - char clientMixBuffer[MAX_PACKET_SIZE]; - - int usecToSleep = AudioConstants::NETWORK_FRAME_USECS; - - const int TRAILING_AVERAGE_FRAMES = 100; - int framesSinceCutoffEvent = TRAILING_AVERAGE_FRAMES; + _idleTimer = new QTimer(); + connect(_idleTimer, SIGNAL(timeout()), this, SLOT(insideLoop())); + _idleTimer->start(0); +} - while (!_isFinished) { - const float STRUGGLE_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD = 0.10f; - const float BACK_OFF_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD = 0.20f; + +void AudioMixer::insideLoop() { + if (_isFinished) { + qDebug() << "AudioMixer::insideLoop stoping _idleTimer"; + _idleTimer->stop(); + delete _idleTimer; + _idleTimer = nullptr; + + QThread *thisThread = QThread::currentThread(); + thisThread->quit(); + + return; + } + + auto nodeList = DependencyManager::get(); + + const float STRUGGLE_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD = 0.10f; + const float BACK_OFF_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD = 0.20f; - const float RATIO_BACK_OFF = 0.02f; + const float RATIO_BACK_OFF = 0.02f; - const float CURRENT_FRAME_RATIO = 1.0f / TRAILING_AVERAGE_FRAMES; - const float PREVIOUS_FRAMES_RATIO = 1.0f - CURRENT_FRAME_RATIO; + const float CURRENT_FRAME_RATIO = 1.0f / TRAILING_AVERAGE_FRAMES; + const float PREVIOUS_FRAMES_RATIO = 1.0f - CURRENT_FRAME_RATIO; - if (usecToSleep < 0) { - usecToSleep = 0; - } + if (_usecToSleep < 0) { + _usecToSleep = 0; + } - _trailingSleepRatio = (PREVIOUS_FRAMES_RATIO * _trailingSleepRatio) - + (usecToSleep * CURRENT_FRAME_RATIO / (float) AudioConstants::NETWORK_FRAME_USECS); + _trailingSleepRatio = (PREVIOUS_FRAMES_RATIO * _trailingSleepRatio) + + (_usecToSleep * CURRENT_FRAME_RATIO / (float) AudioConstants::NETWORK_FRAME_USECS); - float lastCutoffRatio = _performanceThrottlingRatio; - bool hasRatioChanged = false; + float lastCutoffRatio = _performanceThrottlingRatio; + bool hasRatioChanged = false; - if (framesSinceCutoffEvent >= TRAILING_AVERAGE_FRAMES) { - if (_trailingSleepRatio <= STRUGGLE_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD) { - // we're struggling - change our min required loudness to reduce some load - _performanceThrottlingRatio = _performanceThrottlingRatio + (0.5f * (1.0f - _performanceThrottlingRatio)); + if (_framesSinceCutoffEvent >= TRAILING_AVERAGE_FRAMES) { + if (_trailingSleepRatio <= STRUGGLE_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD) { + // we're struggling - change our min required loudness to reduce some load + _performanceThrottlingRatio = _performanceThrottlingRatio + (0.5f * (1.0f - _performanceThrottlingRatio)); - qDebug() << "Mixer is struggling, sleeping" << _trailingSleepRatio * 100 << "% of frame time. Old cutoff was" - << lastCutoffRatio << "and is now" << _performanceThrottlingRatio; - hasRatioChanged = true; - } else if (_trailingSleepRatio >= BACK_OFF_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD && _performanceThrottlingRatio != 0) { - // we've recovered and can back off the required loudness - _performanceThrottlingRatio = _performanceThrottlingRatio - RATIO_BACK_OFF; + qDebug() << "Mixer is struggling, sleeping" << _trailingSleepRatio * 100 << "% of frame time. Old cutoff was" + << lastCutoffRatio << "and is now" << _performanceThrottlingRatio; + hasRatioChanged = true; + } else if (_trailingSleepRatio >= BACK_OFF_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD && _performanceThrottlingRatio != 0) { + // we've recovered and can back off the required loudness + _performanceThrottlingRatio = _performanceThrottlingRatio - RATIO_BACK_OFF; - if (_performanceThrottlingRatio < 0) { - _performanceThrottlingRatio = 0; - } - - qDebug() << "Mixer is recovering, sleeping" << _trailingSleepRatio * 100 << "% of frame time. Old cutoff was" - << lastCutoffRatio << "and is now" << _performanceThrottlingRatio; - hasRatioChanged = true; + if (_performanceThrottlingRatio < 0) { + _performanceThrottlingRatio = 0; } - - if (hasRatioChanged) { - // set out min audability threshold from the new ratio - _minAudibilityThreshold = LOUDNESS_TO_DISTANCE_RATIO / (2.0f * (1.0f - _performanceThrottlingRatio)); - qDebug() << "Minimum audability required to be mixed is now" << _minAudibilityThreshold; - framesSinceCutoffEvent = 0; - } + qDebug() << "Mixer is recovering, sleeping" << _trailingSleepRatio * 100 << "% of frame time. Old cutoff was" + << lastCutoffRatio << "and is now" << _performanceThrottlingRatio; + hasRatioChanged = true; } - - if (!hasRatioChanged) { - ++framesSinceCutoffEvent; - } - - quint64 now = usecTimestampNow(); - if (now - _lastPerSecondCallbackTime > USECS_PER_SECOND) { - perSecondActions(); - _lastPerSecondCallbackTime = now; - } - - nodeList->eachNode([&](const SharedNodePointer& node) { + if (hasRatioChanged) { + // set out min audability threshold from the new ratio + _minAudibilityThreshold = LOUDNESS_TO_DISTANCE_RATIO / (2.0f * (1.0f - _performanceThrottlingRatio)); + qDebug() << "Minimum audability required to be mixed is now" << _minAudibilityThreshold; + + _framesSinceCutoffEvent = 0; + } + } + + if (!hasRatioChanged) { + ++_framesSinceCutoffEvent; + } + + quint64 now = usecTimestampNow(); + if (now - _lastPerSecondCallbackTime > USECS_PER_SECOND) { + perSecondActions(); + _lastPerSecondCallbackTime = now; + } + + nodeList->eachNode([&](const SharedNodePointer& node) { + if (node->getLinkedData()) { AudioMixerClientData* nodeData = (AudioMixerClientData*)node->getLinkedData(); @@ -807,8 +818,8 @@ void AudioMixer::run() { char* mixDataAt; if (streamsMixed > 0) { // pack header - int numBytesMixPacketHeader = populatePacketHeader(clientMixBuffer, PacketTypeMixedAudio); - mixDataAt = clientMixBuffer + numBytesMixPacketHeader; + int numBytesMixPacketHeader = populatePacketHeader(_clientMixBuffer, PacketTypeMixedAudio); + mixDataAt = _clientMixBuffer + numBytesMixPacketHeader; // pack sequence number quint16 sequence = nodeData->getOutgoingSequenceNumber(); @@ -820,8 +831,8 @@ void AudioMixer::run() { mixDataAt += AudioConstants::NETWORK_FRAME_BYTES_STEREO; } else { // pack header - int numBytesPacketHeader = populatePacketHeader(clientMixBuffer, PacketTypeSilentAudioFrame); - mixDataAt = clientMixBuffer + numBytesPacketHeader; + int numBytesPacketHeader = populatePacketHeader(_clientMixBuffer, PacketTypeSilentAudioFrame); + mixDataAt = _clientMixBuffer + numBytesPacketHeader; // pack sequence number quint16 sequence = nodeData->getOutgoingSequenceNumber(); @@ -833,12 +844,12 @@ void AudioMixer::run() { memcpy(mixDataAt, &numSilentSamples, sizeof(quint16)); mixDataAt += sizeof(quint16); } - + // Send audio environment sendAudioEnvironmentPacket(node); // send mixed audio packet - nodeList->writeDatagram(clientMixBuffer, mixDataAt - clientMixBuffer, node); + nodeList->writeDatagram(_clientMixBuffer, mixDataAt - _clientMixBuffer, node); nodeData->incrementOutgoingMixedAudioSequenceNumber(); // send an audio stream stats packet if it's time @@ -852,22 +863,22 @@ void AudioMixer::run() { } }); - ++_numStatFrames; + ++_numStatFrames; - QCoreApplication::processEvents(); + QCoreApplication::processEvents(); - if (_isFinished) { - break; - } + if (_isFinished) { + return; + } - usecToSleep = (++nextFrame * AudioConstants::NETWORK_FRAME_USECS) - timer.nsecsElapsed() / 1000; // ns to us + _usecToSleep = (++_nextFrame * AudioConstants::NETWORK_FRAME_USECS) - _timer.nsecsElapsed() / 1000; // ns to us - if (usecToSleep > 0) { - usleep(usecToSleep); - } + if (_usecToSleep > 0) { + usleep(_usecToSleep); } } + void AudioMixer::perSecondActions() { _sendAudioStreamStats = true; diff --git a/assignment-client/src/audio/AudioMixer.h b/assignment-client/src/audio/AudioMixer.h index 6cee557ff9..a81225a0f2 100644 --- a/assignment-client/src/audio/AudioMixer.h +++ b/assignment-client/src/audio/AudioMixer.h @@ -32,6 +32,7 @@ public: public slots: /// threaded run of assignment void run(); + void insideLoop(); void readPendingDatagrams() { }; // this will not be called since our datagram processing thread will handle void readPendingDatagram(const QByteArray& receivedPacket, const HifiSockAddr& senderSockAddr); @@ -110,6 +111,15 @@ private: MovingMinMaxAvg _timeSpentPerHashMatchCallStats; // update with usecs spent inside each packetVersionAndHashMatch call MovingMinMaxAvg _readPendingCallsPerSecondStats; // update with # of readPendingDatagrams calls in the last second + + // loop variables + QTimer* _idleTimer = nullptr; + int _nextFrame = 0; + QElapsedTimer _timer; + char _clientMixBuffer[MAX_PACKET_SIZE]; + int _usecToSleep = AudioConstants::NETWORK_FRAME_USECS; + const int TRAILING_AVERAGE_FRAMES = 100; + int _framesSinceCutoffEvent = TRAILING_AVERAGE_FRAMES; }; #endif // hifi_AudioMixer_h diff --git a/libraries/networking/src/LimitedNodeList.h b/libraries/networking/src/LimitedNodeList.h index 80ceccc407..cd45fbdbdf 100644 --- a/libraries/networking/src/LimitedNodeList.h +++ b/libraries/networking/src/LimitedNodeList.h @@ -221,6 +221,10 @@ protected: LimitedNodeList(unsigned short socketListenPort = 0, unsigned short dtlsListenPort = 0); LimitedNodeList(LimitedNodeList const&); // Don't implement, needed to avoid copies of singleton void operator=(LimitedNodeList const&); // Don't implement, needed to avoid copies of singleton + + ~LimitedNodeList() { + qDebug() << "XXXXXXXXXXXXXXXXXXXX ~LimitedNodeList called"; + } qint64 writeDatagram(const QByteArray& datagram, const HifiSockAddr& destinationSockAddr, const QUuid& connectionSecret); diff --git a/libraries/networking/src/ThreadedAssignment.cpp b/libraries/networking/src/ThreadedAssignment.cpp index 79b4e7f437..eda3da8479 100644 --- a/libraries/networking/src/ThreadedAssignment.cpp +++ b/libraries/networking/src/ThreadedAssignment.cpp @@ -30,6 +30,17 @@ void ThreadedAssignment::setFinished(bool isFinished) { _isFinished = isFinished; if (_isFinished) { + if (_domainServerTimer) { + _domainServerTimer->stop(); + delete _domainServerTimer; + _domainServerTimer = nullptr; + } + if (_statsTimer) { + _statsTimer->stop(); + delete _statsTimer; + _statsTimer = nullptr; + } + aboutToFinish(); auto nodeList = DependencyManager::get(); @@ -63,15 +74,15 @@ void ThreadedAssignment::commonInit(const QString& targetName, NodeType_t nodeTy // this is a temp fix for Qt 5.3 - rebinding the node socket gives us readyRead for the socket on this thread nodeList->rebindNodeSocket(); - QTimer* domainServerTimer = new QTimer(this); - connect(domainServerTimer, SIGNAL(timeout()), this, SLOT(checkInWithDomainServerOrExit())); - domainServerTimer->start(DOMAIN_SERVER_CHECK_IN_MSECS); + _domainServerTimer = new QTimer(this); + connect(_domainServerTimer, SIGNAL(timeout()), this, SLOT(checkInWithDomainServerOrExit())); + _domainServerTimer->start(DOMAIN_SERVER_CHECK_IN_MSECS); if (shouldSendStats) { // send a stats packet every 1 second - QTimer* statsTimer = new QTimer(this); - connect(statsTimer, &QTimer::timeout, this, &ThreadedAssignment::sendStatsPacket); - statsTimer->start(1000); + _statsTimer = new QTimer(this); + connect(_statsTimer, &QTimer::timeout, this, &ThreadedAssignment::sendStatsPacket); + _statsTimer->start(1000); } } diff --git a/libraries/networking/src/ThreadedAssignment.h b/libraries/networking/src/ThreadedAssignment.h index 454baa85f2..04bee08e62 100644 --- a/libraries/networking/src/ThreadedAssignment.h +++ b/libraries/networking/src/ThreadedAssignment.h @@ -28,8 +28,16 @@ public: public slots: /// threaded run of assignment virtual void run() = 0; + Q_INVOKABLE void stop() { setFinished(true); } virtual void readPendingDatagrams() = 0; virtual void sendStatsPacket(); + +public slots: + virtual void aboutToQuit() { + // emit finished(); + QMetaObject::invokeMethod(this, "stop"); + } + signals: void finished(); @@ -38,6 +46,8 @@ protected: void commonInit(const QString& targetName, NodeType_t nodeType, bool shouldSendStats = true); bool _isFinished; QThread* _datagramProcessingThread; + QTimer* _domainServerTimer = nullptr; + QTimer* _statsTimer = nullptr; private slots: void checkInWithDomainServerOrExit(); From d2cd4fc405f21691855099b8043a03f52f52cdb8 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 29 Apr 2015 11:56:45 -0700 Subject: [PATCH 05/13] types 0 and 1 exit cleanly, type 6 crashes --- assignment-client/src/AssignmentClient.cpp | 7 +- assignment-client/src/AssignmentClientApp.cpp | 2 + assignment-client/src/audio/AudioMixer.cpp | 153 ++++++++---------- assignment-client/src/audio/AudioMixer.h | 17 +- assignment-client/src/avatars/AvatarMixer.cpp | 32 +++- assignment-client/src/avatars/AvatarMixer.h | 5 + .../src/entities/EntityServer.cpp | 22 ++- assignment-client/src/entities/EntityServer.h | 2 + .../src/octree/OctreeInboundPacketProcessor.h | 3 +- assignment-client/src/octree/OctreeServer.cpp | 39 ++++- assignment-client/src/octree/OctreeServer.h | 1 + .../networking/src/ReceivedPacketProcessor.h | 4 +- .../networking/src/ThreadedAssignment.cpp | 18 +++ libraries/networking/src/ThreadedAssignment.h | 6 +- libraries/octree/src/OctreePersistThread.cpp | 1 + libraries/shared/src/DependencyManager.h | 10 +- 16 files changed, 211 insertions(+), 111 deletions(-) diff --git a/assignment-client/src/AssignmentClient.cpp b/assignment-client/src/AssignmentClient.cpp index 5a6868e7e4..dc4d06e52e 100644 --- a/assignment-client/src/AssignmentClient.cpp +++ b/assignment-client/src/AssignmentClient.cpp @@ -116,8 +116,11 @@ void AssignmentClient::stopAssignmentClient() { _statsTimerACM.stop(); if (_currentAssignment) { _currentAssignment->aboutToQuit(); - // _currentAssignment->aboutToFinish(); - _currentAssignment->thread()->wait(); + QThread* currentAssignmentThread = _currentAssignment->thread(); + qDebug() << "main thread waiting on _currentAssignment->thread()" << currentAssignmentThread->objectName(); + currentAssignmentThread->quit(); + currentAssignmentThread->wait(); + qDebug() << "done waiting."; } } diff --git a/assignment-client/src/AssignmentClientApp.cpp b/assignment-client/src/AssignmentClientApp.cpp index 2fcbd67be1..c234daac68 100644 --- a/assignment-client/src/AssignmentClientApp.cpp +++ b/assignment-client/src/AssignmentClientApp.cpp @@ -183,6 +183,8 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) : QThread::currentThread()->setObjectName("main thread"); + DependencyManager::registerInheritance(); + if (numForks || minForks || maxForks) { AssignmentClientMonitor monitor(numForks, minForks, maxForks, requestAssignmentType, assignmentPool, walletUUID, assignmentServerHostname, assignmentServerPort); diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 5d7601ba55..06e6f77f69 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -588,6 +588,7 @@ void AudioMixer::sendStatsPacket() { _sumMixes = 0; _numStatFrames = 0; + // NOTE: These stats can be too large to fit in an MTU, so we break it up into multiple packts... QJsonObject statsObject2; @@ -711,90 +712,78 @@ void AudioMixer::run() { // check the settings object to see if we have anything we can parse out parseSettingsObject(settingsObject); - _nextFrame = 0; - _timer.start(); + int nextFrame = 0; + QElapsedTimer timer; + timer.start(); - _idleTimer = new QTimer(); - connect(_idleTimer, SIGNAL(timeout()), this, SLOT(insideLoop())); - _idleTimer->start(0); -} + char clientMixBuffer[MAX_PACKET_SIZE]; + + int usecToSleep = AudioConstants::NETWORK_FRAME_USECS; + + const int TRAILING_AVERAGE_FRAMES = 100; + int framesSinceCutoffEvent = TRAILING_AVERAGE_FRAMES; - -void AudioMixer::insideLoop() { - if (_isFinished) { - qDebug() << "AudioMixer::insideLoop stoping _idleTimer"; - _idleTimer->stop(); - delete _idleTimer; - _idleTimer = nullptr; - - QThread *thisThread = QThread::currentThread(); - thisThread->quit(); - - return; - } - - auto nodeList = DependencyManager::get(); - - const float STRUGGLE_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD = 0.10f; - const float BACK_OFF_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD = 0.20f; + while (!_isFinished) { + const float STRUGGLE_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD = 0.10f; + const float BACK_OFF_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD = 0.20f; - const float RATIO_BACK_OFF = 0.02f; + const float RATIO_BACK_OFF = 0.02f; - const float CURRENT_FRAME_RATIO = 1.0f / TRAILING_AVERAGE_FRAMES; - const float PREVIOUS_FRAMES_RATIO = 1.0f - CURRENT_FRAME_RATIO; + const float CURRENT_FRAME_RATIO = 1.0f / TRAILING_AVERAGE_FRAMES; + const float PREVIOUS_FRAMES_RATIO = 1.0f - CURRENT_FRAME_RATIO; - if (_usecToSleep < 0) { - _usecToSleep = 0; - } + if (usecToSleep < 0) { + usecToSleep = 0; + } - _trailingSleepRatio = (PREVIOUS_FRAMES_RATIO * _trailingSleepRatio) - + (_usecToSleep * CURRENT_FRAME_RATIO / (float) AudioConstants::NETWORK_FRAME_USECS); + _trailingSleepRatio = (PREVIOUS_FRAMES_RATIO * _trailingSleepRatio) + + (usecToSleep * CURRENT_FRAME_RATIO / (float) AudioConstants::NETWORK_FRAME_USECS); - float lastCutoffRatio = _performanceThrottlingRatio; - bool hasRatioChanged = false; + float lastCutoffRatio = _performanceThrottlingRatio; + bool hasRatioChanged = false; - if (_framesSinceCutoffEvent >= TRAILING_AVERAGE_FRAMES) { - if (_trailingSleepRatio <= STRUGGLE_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD) { - // we're struggling - change our min required loudness to reduce some load - _performanceThrottlingRatio = _performanceThrottlingRatio + (0.5f * (1.0f - _performanceThrottlingRatio)); + if (framesSinceCutoffEvent >= TRAILING_AVERAGE_FRAMES) { + if (_trailingSleepRatio <= STRUGGLE_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD) { + // we're struggling - change our min required loudness to reduce some load + _performanceThrottlingRatio = _performanceThrottlingRatio + (0.5f * (1.0f - _performanceThrottlingRatio)); - qDebug() << "Mixer is struggling, sleeping" << _trailingSleepRatio * 100 << "% of frame time. Old cutoff was" - << lastCutoffRatio << "and is now" << _performanceThrottlingRatio; - hasRatioChanged = true; - } else if (_trailingSleepRatio >= BACK_OFF_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD && _performanceThrottlingRatio != 0) { - // we've recovered and can back off the required loudness - _performanceThrottlingRatio = _performanceThrottlingRatio - RATIO_BACK_OFF; + qDebug() << "Mixer is struggling, sleeping" << _trailingSleepRatio * 100 << "% of frame time. Old cutoff was" + << lastCutoffRatio << "and is now" << _performanceThrottlingRatio; + hasRatioChanged = true; + } else if (_trailingSleepRatio >= BACK_OFF_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD && _performanceThrottlingRatio != 0) { + // we've recovered and can back off the required loudness + _performanceThrottlingRatio = _performanceThrottlingRatio - RATIO_BACK_OFF; - if (_performanceThrottlingRatio < 0) { - _performanceThrottlingRatio = 0; + if (_performanceThrottlingRatio < 0) { + _performanceThrottlingRatio = 0; + } + + qDebug() << "Mixer is recovering, sleeping" << _trailingSleepRatio * 100 << "% of frame time. Old cutoff was" + << lastCutoffRatio << "and is now" << _performanceThrottlingRatio; + hasRatioChanged = true; } - - qDebug() << "Mixer is recovering, sleeping" << _trailingSleepRatio * 100 << "% of frame time. Old cutoff was" - << lastCutoffRatio << "and is now" << _performanceThrottlingRatio; - hasRatioChanged = true; - } - if (hasRatioChanged) { - // set out min audability threshold from the new ratio - _minAudibilityThreshold = LOUDNESS_TO_DISTANCE_RATIO / (2.0f * (1.0f - _performanceThrottlingRatio)); - qDebug() << "Minimum audability required to be mixed is now" << _minAudibilityThreshold; + if (hasRatioChanged) { + // set out min audability threshold from the new ratio + _minAudibilityThreshold = LOUDNESS_TO_DISTANCE_RATIO / (2.0f * (1.0f - _performanceThrottlingRatio)); + qDebug() << "Minimum audability required to be mixed is now" << _minAudibilityThreshold; - _framesSinceCutoffEvent = 0; + framesSinceCutoffEvent = 0; + } } - } - if (!hasRatioChanged) { - ++_framesSinceCutoffEvent; - } + if (!hasRatioChanged) { + ++framesSinceCutoffEvent; + } - quint64 now = usecTimestampNow(); - if (now - _lastPerSecondCallbackTime > USECS_PER_SECOND) { - perSecondActions(); - _lastPerSecondCallbackTime = now; - } + quint64 now = usecTimestampNow(); + if (now - _lastPerSecondCallbackTime > USECS_PER_SECOND) { + perSecondActions(); + _lastPerSecondCallbackTime = now; + } - nodeList->eachNode([&](const SharedNodePointer& node) { - + nodeList->eachNode([&](const SharedNodePointer& node) { + if (node->getLinkedData()) { AudioMixerClientData* nodeData = (AudioMixerClientData*)node->getLinkedData(); @@ -818,8 +807,8 @@ void AudioMixer::insideLoop() { char* mixDataAt; if (streamsMixed > 0) { // pack header - int numBytesMixPacketHeader = populatePacketHeader(_clientMixBuffer, PacketTypeMixedAudio); - mixDataAt = _clientMixBuffer + numBytesMixPacketHeader; + int numBytesMixPacketHeader = populatePacketHeader(clientMixBuffer, PacketTypeMixedAudio); + mixDataAt = clientMixBuffer + numBytesMixPacketHeader; // pack sequence number quint16 sequence = nodeData->getOutgoingSequenceNumber(); @@ -831,8 +820,8 @@ void AudioMixer::insideLoop() { mixDataAt += AudioConstants::NETWORK_FRAME_BYTES_STEREO; } else { // pack header - int numBytesPacketHeader = populatePacketHeader(_clientMixBuffer, PacketTypeSilentAudioFrame); - mixDataAt = _clientMixBuffer + numBytesPacketHeader; + int numBytesPacketHeader = populatePacketHeader(clientMixBuffer, PacketTypeSilentAudioFrame); + mixDataAt = clientMixBuffer + numBytesPacketHeader; // pack sequence number quint16 sequence = nodeData->getOutgoingSequenceNumber(); @@ -844,12 +833,12 @@ void AudioMixer::insideLoop() { memcpy(mixDataAt, &numSilentSamples, sizeof(quint16)); mixDataAt += sizeof(quint16); } - + // Send audio environment sendAudioEnvironmentPacket(node); // send mixed audio packet - nodeList->writeDatagram(_clientMixBuffer, mixDataAt - _clientMixBuffer, node); + nodeList->writeDatagram(clientMixBuffer, mixDataAt - clientMixBuffer, node); nodeData->incrementOutgoingMixedAudioSequenceNumber(); // send an audio stream stats packet if it's time @@ -863,22 +852,22 @@ void AudioMixer::insideLoop() { } }); - ++_numStatFrames; + ++_numStatFrames; - QCoreApplication::processEvents(); + QCoreApplication::processEvents(); - if (_isFinished) { - return; - } + if (_isFinished) { + break; + } - _usecToSleep = (++_nextFrame * AudioConstants::NETWORK_FRAME_USECS) - _timer.nsecsElapsed() / 1000; // ns to us + usecToSleep = (++nextFrame * AudioConstants::NETWORK_FRAME_USECS) - timer.nsecsElapsed() / 1000; // ns to us - if (_usecToSleep > 0) { - usleep(_usecToSleep); + if (usecToSleep > 0) { + usleep(usecToSleep); + } } } - void AudioMixer::perSecondActions() { _sendAudioStreamStats = true; diff --git a/assignment-client/src/audio/AudioMixer.h b/assignment-client/src/audio/AudioMixer.h index a81225a0f2..4894f91e01 100644 --- a/assignment-client/src/audio/AudioMixer.h +++ b/assignment-client/src/audio/AudioMixer.h @@ -32,7 +32,6 @@ public: public slots: /// threaded run of assignment void run(); - void insideLoop(); void readPendingDatagrams() { }; // this will not be called since our datagram processing thread will handle void readPendingDatagram(const QByteArray& receivedPacket, const HifiSockAddr& senderSockAddr); @@ -112,14 +111,14 @@ private: MovingMinMaxAvg _readPendingCallsPerSecondStats; // update with # of readPendingDatagrams calls in the last second - // loop variables - QTimer* _idleTimer = nullptr; - int _nextFrame = 0; - QElapsedTimer _timer; - char _clientMixBuffer[MAX_PACKET_SIZE]; - int _usecToSleep = AudioConstants::NETWORK_FRAME_USECS; - const int TRAILING_AVERAGE_FRAMES = 100; - int _framesSinceCutoffEvent = TRAILING_AVERAGE_FRAMES; + /* // loop variables */ + /* // QTimer* _idleTimer = nullptr; */ + /* int _nextFrame = 0; */ + /* QElapsedTimer _timer; */ + /* char _clientMixBuffer[MAX_PACKET_SIZE]; */ + /* int _usecToSleep = AudioConstants::NETWORK_FRAME_USECS; */ + /* const int TRAILING_AVERAGE_FRAMES = 100; */ + /* int _framesSinceCutoffEvent = TRAILING_AVERAGE_FRAMES; */ }; #endif // hifi_AudioMixer_h diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index dae6af3fc5..8cff7d705d 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -45,6 +45,10 @@ AvatarMixer::AvatarMixer(const QByteArray& packet) : } AvatarMixer::~AvatarMixer() { + qDebug() << "AvatarMixer::~AvatarMixer"; + if (_broadcastTimer) { + _broadcastTimer->deleteLater(); + } _broadcastThread.quit(); _broadcastThread.wait(); } @@ -61,9 +65,7 @@ const float BILLBOARD_AND_IDENTITY_SEND_PROBABILITY = 1.0f / 300.0f; // 1) use the view frustum to cull those avatars that are out of view. Since avatar data doesn't need to be present // if the avatar is not in view or in the keyhole. void AvatarMixer::broadcastAvatarData() { - int idleTime = QDateTime::currentMSecsSinceEpoch() - _lastFrameTimestamp; - ++_numStatFrames; const float STRUGGLE_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD = 0.10f; @@ -334,6 +336,22 @@ void AvatarMixer::sendStatsPacket() { _numStatFrames = 0; } +// void AvatarMixer::stop() { +// qDebug() << "AvatarMixer::stop"; +// if (_broadcastTimer) { +// // _broadcastTimer->stop(); +// // delete _broadcastTimer; +// _broadcastTimer->deleteLater(); +// // _broadcastTimer = nullptr; +// } + +// _broadcastThread.quit(); +// _broadcastThread.wait(); + +// ThreadedAssignment::stop(); +// } + + void AvatarMixer::run() { ThreadedAssignment::commonInit(AVATAR_MIXER_LOGGING_NAME, NodeType::AvatarMixer); @@ -343,13 +361,13 @@ void AvatarMixer::run() { nodeList->linkedDataCreateCallback = attachAvatarDataToNode; // setup the timer that will be fired on the broadcast thread - QTimer* broadcastTimer = new QTimer(); - broadcastTimer->setInterval(AVATAR_DATA_SEND_INTERVAL_MSECS); - broadcastTimer->moveToThread(&_broadcastThread); + _broadcastTimer = new QTimer(); + _broadcastTimer->setInterval(AVATAR_DATA_SEND_INTERVAL_MSECS); + _broadcastTimer->moveToThread(&_broadcastThread); // connect appropriate signals and slots - connect(broadcastTimer, &QTimer::timeout, this, &AvatarMixer::broadcastAvatarData, Qt::DirectConnection); - connect(&_broadcastThread, SIGNAL(started()), broadcastTimer, SLOT(start())); + connect(_broadcastTimer, &QTimer::timeout, this, &AvatarMixer::broadcastAvatarData, Qt::DirectConnection); + connect(&_broadcastThread, SIGNAL(started()), _broadcastTimer, SLOT(start())); // start the broadcastThread _broadcastThread.start(); diff --git a/assignment-client/src/avatars/AvatarMixer.h b/assignment-client/src/avatars/AvatarMixer.h index a69019427b..2a659cface 100644 --- a/assignment-client/src/avatars/AvatarMixer.h +++ b/assignment-client/src/avatars/AvatarMixer.h @@ -25,6 +25,7 @@ public: public slots: /// runs the avatar mixer void run(); + // Q_INVOKABLE virtual void stop(); void nodeAdded(SharedNodePointer nodeAdded); void nodeKilled(SharedNodePointer killedNode); @@ -32,6 +33,8 @@ public slots: void readPendingDatagrams(); void sendStatsPacket(); + + void finished(); private: void broadcastAvatarData(); @@ -47,6 +50,8 @@ private: int _numStatFrames; int _sumBillboardPackets; int _sumIdentityPackets; + + QTimer* _broadcastTimer = nullptr; }; #endif // hifi_AvatarMixer_h diff --git a/assignment-client/src/entities/EntityServer.cpp b/assignment-client/src/entities/EntityServer.cpp index 85d0a7414c..e38d0e3c65 100644 --- a/assignment-client/src/entities/EntityServer.cpp +++ b/assignment-client/src/entities/EntityServer.cpp @@ -27,6 +27,13 @@ EntityServer::EntityServer(const QByteArray& packet) } EntityServer::~EntityServer() { + qDebug() << "EntityServer::~EntityServer"; + + if (_pruneDeletedEntitiesTimer) { + _pruneDeletedEntitiesTimer->stop(); + _pruneDeletedEntitiesTimer->deleteLater(); + } + EntityTree* tree = (EntityTree*)_tree; tree->removeNewlyCreatedHook(this); } @@ -48,10 +55,10 @@ Octree* EntityServer::createTree() { } void EntityServer::beforeRun() { - QTimer* pruneDeletedEntitiesTimer = new QTimer(this); - connect(pruneDeletedEntitiesTimer, SIGNAL(timeout()), this, SLOT(pruneDeletedEntities())); + _pruneDeletedEntitiesTimer = new QTimer(this); + connect(_pruneDeletedEntitiesTimer, SIGNAL(timeout()), this, SLOT(pruneDeletedEntities())); const int PRUNE_DELETED_MODELS_INTERVAL_MSECS = 1 * 1000; // once every second - pruneDeletedEntitiesTimer->start(PRUNE_DELETED_MODELS_INTERVAL_MSECS); + _pruneDeletedEntitiesTimer->start(PRUNE_DELETED_MODELS_INTERVAL_MSECS); } void EntityServer::entityCreated(const EntityItem& newEntity, const SharedNodePointer& senderNode) { @@ -158,3 +165,12 @@ void EntityServer::readAdditionalConfiguration(const QJsonObject& settingsSectio } +// void EntityServer::stop() { +// qDebug() << "EntityServer::stop"; +// if (_pruneDeletedEntitiesTimer) { +// _pruneDeletedEntitiesTimer->stop(); +// delete _pruneDeletedEntitiesTimer; +// _pruneDeletedEntitiesTimer = nullptr; +// } +// OctreeServer::stop(); +// } diff --git a/assignment-client/src/entities/EntityServer.h b/assignment-client/src/entities/EntityServer.h index d8c2e39f3b..78c20d039c 100644 --- a/assignment-client/src/entities/EntityServer.h +++ b/assignment-client/src/entities/EntityServer.h @@ -44,6 +44,7 @@ public: virtual void readAdditionalConfiguration(const QJsonObject& settingsSectionObject); public slots: + // Q_INVOKABLE virtual void stop(); void pruneDeletedEntities(); protected: @@ -51,6 +52,7 @@ protected: private: EntitySimulation* _entitySimulation; + QTimer* _pruneDeletedEntitiesTimer = nullptr; }; #endif // hifi_EntityServer_h diff --git a/assignment-client/src/octree/OctreeInboundPacketProcessor.h b/assignment-client/src/octree/OctreeInboundPacketProcessor.h index 8f07f9d566..2f9c060183 100644 --- a/assignment-client/src/octree/OctreeInboundPacketProcessor.h +++ b/assignment-client/src/octree/OctreeInboundPacketProcessor.h @@ -74,7 +74,8 @@ public: NodeToSenderStatsMap& getSingleSenderStats() { return _singleSenderStats; } - void shuttingDown() { _shuttingDown = true;} + // void shuttingDown() { _shuttingDown = true;} + virtual void terminating() { _shuttingDown = true; ReceivedPacketProcessor::terminating(); } protected: diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index 266183745f..725f4eda2c 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -266,16 +266,19 @@ OctreeServer::~OctreeServer() { } if (_jurisdictionSender) { + _jurisdictionSender->terminating(); _jurisdictionSender->terminate(); _jurisdictionSender->deleteLater(); } if (_octreeInboundPacketProcessor) { + _octreeInboundPacketProcessor->terminating(); _octreeInboundPacketProcessor->terminate(); _octreeInboundPacketProcessor->deleteLater(); } if (_persistThread) { + _persistThread->terminating(); _persistThread->terminate(); _persistThread->deleteLater(); } @@ -1219,7 +1222,7 @@ void OctreeServer::forceNodeShutdown(SharedNodePointer node) { void OctreeServer::aboutToFinish() { qDebug() << qPrintable(_safeServerName) << "server STARTING about to finish..."; qDebug() << qPrintable(_safeServerName) << "inform Octree Inbound Packet Processor that we are shutting down..."; - _octreeInboundPacketProcessor->shuttingDown(); + _octreeInboundPacketProcessor->terminating(); DependencyManager::get()->eachNode([this](const SharedNodePointer& node) { qDebug() << qPrintable(_safeServerName) << "server about to finish while node still connected node:" << *node; @@ -1233,6 +1236,40 @@ void OctreeServer::aboutToFinish() { qDebug() << qPrintable(_safeServerName) << "server ENDING about to finish..."; } + +// void OctreeServer::stop() { +// qDebug() << "OctreeServer::stop"; +// // setFinished(true); +// // QThread *thisThread = QThread::currentThread(); +// // thisThread->quit(); + +// if (_jurisdictionSender) { +// _jurisdictionSender->terminating(); +// _jurisdictionSender->terminate(); +// // delete _jurisdictionSender; +// // _jurisdictionSender = nullptr; +// } + +// _datagramProcessingThread->quit(); +// if (_octreeInboundPacketProcessor) { +// _octreeInboundPacketProcessor->terminating(); +// _octreeInboundPacketProcessor->terminate(); +// // delete _octreeInboundPacketProcessor; +// // _octreeInboundPacketProcessor = nullptr; +// } + +// // _persistThread +// if (_persistThread) { +// _persistThread->terminating(); +// _persistThread->terminate(); +// // delete _persistThread; +// // _persistThread = nullptr; +// } + +// ThreadedAssignment::stop(); +// } + + QString OctreeServer::getUptime() { QString formattedUptime; quint64 now = usecTimestampNow(); diff --git a/assignment-client/src/octree/OctreeServer.h b/assignment-client/src/octree/OctreeServer.h index 41cd3259cf..10c4e81262 100644 --- a/assignment-client/src/octree/OctreeServer.h +++ b/assignment-client/src/octree/OctreeServer.h @@ -123,6 +123,7 @@ public: public slots: /// runs the octree server assignment void run(); + // Q_INVOKABLE virtual void stop(); void nodeAdded(SharedNodePointer node); void nodeKilled(SharedNodePointer node); void sendStatsPacket(); diff --git a/libraries/networking/src/ReceivedPacketProcessor.h b/libraries/networking/src/ReceivedPacketProcessor.h index d5fc006882..bcc9f9a1f5 100644 --- a/libraries/networking/src/ReceivedPacketProcessor.h +++ b/libraries/networking/src/ReceivedPacketProcessor.h @@ -47,6 +47,8 @@ public: /// How many received packets waiting are to be processed int packetsToProcessCount() const { return _packets.size(); } + virtual void terminating(); + public slots: void nodeKilled(SharedNodePointer node); @@ -71,8 +73,6 @@ protected: /// Override to do work after the packets processing loop. Default does nothing. virtual void postProcess() { } - virtual void terminating(); - protected: QVector _packets; diff --git a/libraries/networking/src/ThreadedAssignment.cpp b/libraries/networking/src/ThreadedAssignment.cpp index eda3da8479..c212aab188 100644 --- a/libraries/networking/src/ThreadedAssignment.cpp +++ b/libraries/networking/src/ThreadedAssignment.cpp @@ -26,7 +26,14 @@ ThreadedAssignment::ThreadedAssignment(const QByteArray& packet) : } +ThreadedAssignment::~ThreadedAssignment() { + // setFinished(true); +} + void ThreadedAssignment::setFinished(bool isFinished) { + + qDebug() << "------------- ThreadedAssignment::setFinished" << isFinished << " -------------------"; + _isFinished = isFinished; if (_isFinished) { @@ -50,8 +57,10 @@ void ThreadedAssignment::setFinished(bool isFinished) { if (_datagramProcessingThread) { // tell the datagram processing thread to quit and wait until it is done, then return the node socket to the NodeList + qDebug() << "stopping datagramProcessingThread..."; _datagramProcessingThread->quit(); _datagramProcessingThread->wait(); + qDebug() << "done stopping datagramProcessingThread."; // set node socket parent back to NodeList nodeList->getNodeSocket().setParent(nodeList.data()); @@ -64,6 +73,15 @@ void ThreadedAssignment::setFinished(bool isFinished) { } } + +// void ThreadedAssignment::stop() { +// setFinished(true); +// qDebug() << "ThreadedAssignment::stop"; +// QThread *thisThread = QThread::currentThread(); +// thisThread->quit(); +// } + + void ThreadedAssignment::commonInit(const QString& targetName, NodeType_t nodeType, bool shouldSendStats) { // change the logging target name while the assignment is running LogHandler::getInstance().setTargetName(targetName); diff --git a/libraries/networking/src/ThreadedAssignment.h b/libraries/networking/src/ThreadedAssignment.h index 04bee08e62..e2c6e0a1b6 100644 --- a/libraries/networking/src/ThreadedAssignment.h +++ b/libraries/networking/src/ThreadedAssignment.h @@ -20,6 +20,7 @@ class ThreadedAssignment : public Assignment { Q_OBJECT public: ThreadedAssignment(const QByteArray& packet); + virtual ~ThreadedAssignment(); void setFinished(bool isFinished); virtual void aboutToFinish() { }; @@ -28,14 +29,13 @@ public: public slots: /// threaded run of assignment virtual void run() = 0; - Q_INVOKABLE void stop() { setFinished(true); } + Q_INVOKABLE virtual void stop() { setFinished(true); } virtual void readPendingDatagrams() = 0; virtual void sendStatsPacket(); public slots: virtual void aboutToQuit() { - // emit finished(); - QMetaObject::invokeMethod(this, "stop"); + QMetaObject::invokeMethod(this, "stop"); } signals: diff --git a/libraries/octree/src/OctreePersistThread.cpp b/libraries/octree/src/OctreePersistThread.cpp index 210d074001..52dd2aa4ca 100644 --- a/libraries/octree/src/OctreePersistThread.cpp +++ b/libraries/octree/src/OctreePersistThread.cpp @@ -228,6 +228,7 @@ void OctreePersistThread::aboutToFinish() { qCDebug(octree) << "Persist thread about to finish..."; persist(); qCDebug(octree) << "Persist thread done with about to finish..."; + _stopThread = true; } void OctreePersistThread::persist() { diff --git a/libraries/shared/src/DependencyManager.h b/libraries/shared/src/DependencyManager.h index 01b755fdd0..1d91872940 100644 --- a/libraries/shared/src/DependencyManager.h +++ b/libraries/shared/src/DependencyManager.h @@ -26,15 +26,21 @@ class Dependency { public: typedef std::function DeleterFunction; + const QString& getDependencyName() { return _name; } protected: - virtual ~Dependency() {} + virtual ~Dependency() { + qDebug() << "DESTRUCTING" << _name; + } virtual void customDeleter() { _customDeleter(this); } void setCustomDeleter(DeleterFunction customDeleter) { _customDeleter = customDeleter; } DeleterFunction _customDeleter = [](Dependency* pointer) { delete pointer; }; + + void setDependencyName(QString name) { _name = name; } + QString _name; friend class DependencyManager; }; @@ -95,6 +101,7 @@ QSharedPointer DependencyManager::set(Args&&... args) { QSharedPointer newInstance(new T(args...), &T::customDeleter); QSharedPointer storedInstance = qSharedPointerCast(newInstance); instance.swap(storedInstance); + newInstance->setDependencyName(typeid(T).name()); return newInstance; } @@ -102,6 +109,7 @@ QSharedPointer DependencyManager::set(Args&&... args) { template void DependencyManager::destroy() { static size_t hashCode = _manager.getHashCode(); + qDebug() << "DESTROYING" << _manager.safeGet(hashCode)->getDependencyName(); _manager.safeGet(hashCode).clear(); } From e7d8bccd5d299887792b613e44f555cf749d225c Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 29 Apr 2015 12:03:54 -0700 Subject: [PATCH 06/13] cleanups --- assignment-client/src/audio/AudioMixer.h | 9 ----- assignment-client/src/avatars/AvatarMixer.cpp | 18 ++-------- assignment-client/src/avatars/AvatarMixer.h | 3 -- .../src/entities/EntityServer.cpp | 11 ------ assignment-client/src/entities/EntityServer.h | 1 - assignment-client/src/octree/OctreeServer.cpp | 34 ------------------- assignment-client/src/octree/OctreeServer.h | 1 - .../networking/src/ThreadedAssignment.cpp | 9 ----- 8 files changed, 2 insertions(+), 84 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.h b/assignment-client/src/audio/AudioMixer.h index 4894f91e01..6cee557ff9 100644 --- a/assignment-client/src/audio/AudioMixer.h +++ b/assignment-client/src/audio/AudioMixer.h @@ -110,15 +110,6 @@ private: MovingMinMaxAvg _timeSpentPerHashMatchCallStats; // update with usecs spent inside each packetVersionAndHashMatch call MovingMinMaxAvg _readPendingCallsPerSecondStats; // update with # of readPendingDatagrams calls in the last second - - /* // loop variables */ - /* // QTimer* _idleTimer = nullptr; */ - /* int _nextFrame = 0; */ - /* QElapsedTimer _timer; */ - /* char _clientMixBuffer[MAX_PACKET_SIZE]; */ - /* int _usecToSleep = AudioConstants::NETWORK_FRAME_USECS; */ - /* const int TRAILING_AVERAGE_FRAMES = 100; */ - /* int _framesSinceCutoffEvent = TRAILING_AVERAGE_FRAMES; */ }; #endif // hifi_AudioMixer_h diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index 8cff7d705d..5612450f1f 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -65,7 +65,9 @@ const float BILLBOARD_AND_IDENTITY_SEND_PROBABILITY = 1.0f / 300.0f; // 1) use the view frustum to cull those avatars that are out of view. Since avatar data doesn't need to be present // if the avatar is not in view or in the keyhole. void AvatarMixer::broadcastAvatarData() { + int idleTime = QDateTime::currentMSecsSinceEpoch() - _lastFrameTimestamp; + ++_numStatFrames; const float STRUGGLE_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD = 0.10f; @@ -336,22 +338,6 @@ void AvatarMixer::sendStatsPacket() { _numStatFrames = 0; } -// void AvatarMixer::stop() { -// qDebug() << "AvatarMixer::stop"; -// if (_broadcastTimer) { -// // _broadcastTimer->stop(); -// // delete _broadcastTimer; -// _broadcastTimer->deleteLater(); -// // _broadcastTimer = nullptr; -// } - -// _broadcastThread.quit(); -// _broadcastThread.wait(); - -// ThreadedAssignment::stop(); -// } - - void AvatarMixer::run() { ThreadedAssignment::commonInit(AVATAR_MIXER_LOGGING_NAME, NodeType::AvatarMixer); diff --git a/assignment-client/src/avatars/AvatarMixer.h b/assignment-client/src/avatars/AvatarMixer.h index 2a659cface..4746f02d14 100644 --- a/assignment-client/src/avatars/AvatarMixer.h +++ b/assignment-client/src/avatars/AvatarMixer.h @@ -25,7 +25,6 @@ public: public slots: /// runs the avatar mixer void run(); - // Q_INVOKABLE virtual void stop(); void nodeAdded(SharedNodePointer nodeAdded); void nodeKilled(SharedNodePointer killedNode); @@ -33,8 +32,6 @@ public slots: void readPendingDatagrams(); void sendStatsPacket(); - - void finished(); private: void broadcastAvatarData(); diff --git a/assignment-client/src/entities/EntityServer.cpp b/assignment-client/src/entities/EntityServer.cpp index e38d0e3c65..b2a1c62ed4 100644 --- a/assignment-client/src/entities/EntityServer.cpp +++ b/assignment-client/src/entities/EntityServer.cpp @@ -163,14 +163,3 @@ void EntityServer::readAdditionalConfiguration(const QJsonObject& settingsSectio EntityTree* tree = static_cast(_tree); tree->setWantEditLogging(wantEditLogging); } - - -// void EntityServer::stop() { -// qDebug() << "EntityServer::stop"; -// if (_pruneDeletedEntitiesTimer) { -// _pruneDeletedEntitiesTimer->stop(); -// delete _pruneDeletedEntitiesTimer; -// _pruneDeletedEntitiesTimer = nullptr; -// } -// OctreeServer::stop(); -// } diff --git a/assignment-client/src/entities/EntityServer.h b/assignment-client/src/entities/EntityServer.h index 78c20d039c..9edec7b704 100644 --- a/assignment-client/src/entities/EntityServer.h +++ b/assignment-client/src/entities/EntityServer.h @@ -44,7 +44,6 @@ public: virtual void readAdditionalConfiguration(const QJsonObject& settingsSectionObject); public slots: - // Q_INVOKABLE virtual void stop(); void pruneDeletedEntities(); protected: diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index 725f4eda2c..506733e13d 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -1236,40 +1236,6 @@ void OctreeServer::aboutToFinish() { qDebug() << qPrintable(_safeServerName) << "server ENDING about to finish..."; } - -// void OctreeServer::stop() { -// qDebug() << "OctreeServer::stop"; -// // setFinished(true); -// // QThread *thisThread = QThread::currentThread(); -// // thisThread->quit(); - -// if (_jurisdictionSender) { -// _jurisdictionSender->terminating(); -// _jurisdictionSender->terminate(); -// // delete _jurisdictionSender; -// // _jurisdictionSender = nullptr; -// } - -// _datagramProcessingThread->quit(); -// if (_octreeInboundPacketProcessor) { -// _octreeInboundPacketProcessor->terminating(); -// _octreeInboundPacketProcessor->terminate(); -// // delete _octreeInboundPacketProcessor; -// // _octreeInboundPacketProcessor = nullptr; -// } - -// // _persistThread -// if (_persistThread) { -// _persistThread->terminating(); -// _persistThread->terminate(); -// // delete _persistThread; -// // _persistThread = nullptr; -// } - -// ThreadedAssignment::stop(); -// } - - QString OctreeServer::getUptime() { QString formattedUptime; quint64 now = usecTimestampNow(); diff --git a/assignment-client/src/octree/OctreeServer.h b/assignment-client/src/octree/OctreeServer.h index 10c4e81262..41cd3259cf 100644 --- a/assignment-client/src/octree/OctreeServer.h +++ b/assignment-client/src/octree/OctreeServer.h @@ -123,7 +123,6 @@ public: public slots: /// runs the octree server assignment void run(); - // Q_INVOKABLE virtual void stop(); void nodeAdded(SharedNodePointer node); void nodeKilled(SharedNodePointer node); void sendStatsPacket(); diff --git a/libraries/networking/src/ThreadedAssignment.cpp b/libraries/networking/src/ThreadedAssignment.cpp index c212aab188..6ec47d7cdd 100644 --- a/libraries/networking/src/ThreadedAssignment.cpp +++ b/libraries/networking/src/ThreadedAssignment.cpp @@ -73,15 +73,6 @@ void ThreadedAssignment::setFinished(bool isFinished) { } } - -// void ThreadedAssignment::stop() { -// setFinished(true); -// qDebug() << "ThreadedAssignment::stop"; -// QThread *thisThread = QThread::currentThread(); -// thisThread->quit(); -// } - - void ThreadedAssignment::commonInit(const QString& targetName, NodeType_t nodeType, bool shouldSendStats) { // change the logging target name while the assignment is running LogHandler::getInstance().setTargetName(targetName); From 009bb9dc710fe34376ff546050899e6320332457 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 29 Apr 2015 15:16:00 -0700 Subject: [PATCH 07/13] all 4 types of assignment-client appear to exit cleanly, now --- assignment-client/src/AssignmentClient.cpp | 8 ++++++++ assignment-client/src/AssignmentClientApp.cpp | 3 --- .../src/AssignmentClientMonitor.cpp | 2 ++ .../src/entities/EntityServer.cpp | 2 ++ assignment-client/src/octree/OctreeServer.cpp | 18 ++++++++++++++---- assignment-client/src/octree/OctreeServer.h | 3 +++ libraries/networking/src/LimitedNodeList.h | 4 +--- libraries/networking/src/NodeList.h | 5 +++++ libraries/shared/src/LogHandler.h | 6 ++++++ 9 files changed, 41 insertions(+), 10 deletions(-) diff --git a/assignment-client/src/AssignmentClient.cpp b/assignment-client/src/AssignmentClient.cpp index dc4d06e52e..4f00b30f42 100644 --- a/assignment-client/src/AssignmentClient.cpp +++ b/assignment-client/src/AssignmentClient.cpp @@ -126,7 +126,15 @@ void AssignmentClient::stopAssignmentClient() { void AssignmentClient::aboutToQuit() { + qDebug() << "AssignmentClient::aboutToQuit start"; stopAssignmentClient(); + qDebug() << "AssignmentClient::aboutToQuit end"; + // clear the log handler so that Qt doesn't call the destructor on LogHandler + qInstallMessageHandler(0); + // clear out pointer to the assignment so the destructor gets called. if we don't do this here, + // it will get destroyed along with all the other "static" stuff. various static member variables + // will be destroyed first and things go wrong. + _currentAssignment.clear(); } diff --git a/assignment-client/src/AssignmentClientApp.cpp b/assignment-client/src/AssignmentClientApp.cpp index c234daac68..d8e4306ec5 100644 --- a/assignment-client/src/AssignmentClientApp.cpp +++ b/assignment-client/src/AssignmentClientApp.cpp @@ -167,7 +167,6 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) : } - if (parser.isSet(numChildsOption)) { if (minForks && minForks > numForks) { qCritical() << "--min can't be more than -n"; @@ -189,8 +188,6 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) : AssignmentClientMonitor monitor(numForks, minForks, maxForks, requestAssignmentType, assignmentPool, walletUUID, assignmentServerHostname, assignmentServerPort); connect(this, &QCoreApplication::aboutToQuit, &monitor, &AssignmentClientMonitor::aboutToQuit); - - exec(); } else { AssignmentClient client(ppid, requestAssignmentType, assignmentPool, diff --git a/assignment-client/src/AssignmentClientMonitor.cpp b/assignment-client/src/AssignmentClientMonitor.cpp index 14eb93ad6e..31743ea630 100644 --- a/assignment-client/src/AssignmentClientMonitor.cpp +++ b/assignment-client/src/AssignmentClientMonitor.cpp @@ -83,6 +83,8 @@ void AssignmentClientMonitor::stopChildProcesses() { void AssignmentClientMonitor::aboutToQuit() { stopChildProcesses(); + // clear the log handler so that Qt doesn't call the destructor on LogHandler + qInstallMessageHandler(0); } diff --git a/assignment-client/src/entities/EntityServer.cpp b/assignment-client/src/entities/EntityServer.cpp index b2a1c62ed4..a175eef475 100644 --- a/assignment-client/src/entities/EntityServer.cpp +++ b/assignment-client/src/entities/EntityServer.cpp @@ -163,3 +163,5 @@ void EntityServer::readAdditionalConfiguration(const QJsonObject& settingsSectio EntityTree* tree = static_cast(_tree); tree->setWantEditLogging(wantEditLogging); } + + diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index 506733e13d..11509192ad 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -239,8 +239,10 @@ OctreeServer::OctreeServer(const QByteArray& packet) : _octreeInboundPacketProcessor(NULL), _persistThread(NULL), _started(time(0)), - _startedUSecs(usecTimestampNow()) + _startedUSecs(usecTimestampNow()), + _nodeList(DependencyManager::get()) { + if (_instance) { qDebug() << "Octree Server starting... while old instance still running _instance=["<<_instance<<"] this=[" << this << "]"; } @@ -1098,7 +1100,7 @@ void OctreeServer::readConfiguration() { } void OctreeServer::run() { - qInstallMessageHandler(LogHandler::verboseMessageHandler); + // qInstallMessageHandler(LogHandler::verboseMessageHandler); _safeServerName = getMyServerName(); @@ -1222,8 +1224,15 @@ void OctreeServer::forceNodeShutdown(SharedNodePointer node) { void OctreeServer::aboutToFinish() { qDebug() << qPrintable(_safeServerName) << "server STARTING about to finish..."; qDebug() << qPrintable(_safeServerName) << "inform Octree Inbound Packet Processor that we are shutting down..."; - _octreeInboundPacketProcessor->terminating(); - + + if (_octreeInboundPacketProcessor) { + _octreeInboundPacketProcessor->terminating(); + } + + if (_jurisdictionSender) { + _jurisdictionSender->terminating(); + } + DependencyManager::get()->eachNode([this](const SharedNodePointer& node) { qDebug() << qPrintable(_safeServerName) << "server about to finish while node still connected node:" << *node; forceNodeShutdown(node); @@ -1231,6 +1240,7 @@ void OctreeServer::aboutToFinish() { if (_persistThread) { _persistThread->aboutToFinish(); + _persistThread->terminating(); } qDebug() << qPrintable(_safeServerName) << "server ENDING about to finish..."; diff --git a/assignment-client/src/octree/OctreeServer.h b/assignment-client/src/octree/OctreeServer.h index 41cd3259cf..09368fbe4d 100644 --- a/assignment-client/src/octree/OctreeServer.h +++ b/assignment-client/src/octree/OctreeServer.h @@ -238,6 +238,9 @@ protected: static QMutex _threadsDidPacketDistributorMutex; static QMutex _threadsDidHandlePacketSendMutex; static QMutex _threadsDidCallWriteDatagramMutex; + + // keep a pointer to node list so that it doesn't get shut down before this class. + QSharedPointer _nodeList; }; #endif // hifi_OctreeServer_h diff --git a/libraries/networking/src/LimitedNodeList.h b/libraries/networking/src/LimitedNodeList.h index cd45fbdbdf..f541a29d01 100644 --- a/libraries/networking/src/LimitedNodeList.h +++ b/libraries/networking/src/LimitedNodeList.h @@ -222,7 +222,7 @@ protected: LimitedNodeList(LimitedNodeList const&); // Don't implement, needed to avoid copies of singleton void operator=(LimitedNodeList const&); // Don't implement, needed to avoid copies of singleton - ~LimitedNodeList() { + virtual ~LimitedNodeList() { qDebug() << "XXXXXXXXXXXXXXXXXXXX ~LimitedNodeList called"; } @@ -241,8 +241,6 @@ protected: HifiSockAddr _localSockAddr; HifiSockAddr _publicSockAddr; HifiSockAddr _stunSockAddr; - - QTimer* _silentNodeTimer; // XXX can BandwidthRecorder be used for this? int _numCollectedPackets; diff --git a/libraries/networking/src/NodeList.h b/libraries/networking/src/NodeList.h index ccfaa7a4cf..4cb3fb8ea2 100644 --- a/libraries/networking/src/NodeList.h +++ b/libraries/networking/src/NodeList.h @@ -45,6 +45,11 @@ class NodeList : public LimitedNodeList { SINGLETON_DEPENDENCY public: + virtual ~NodeList() { + qDebug() << "XXXXXXXXXXXXXXXXXXXX ~NodeList called"; + } + + NodeType_t getOwnerType() const { return _ownerType; } void setOwnerType(NodeType_t ownerType) { _ownerType = ownerType; } diff --git a/libraries/shared/src/LogHandler.h b/libraries/shared/src/LogHandler.h index 914cad212d..1e9567b4d7 100644 --- a/libraries/shared/src/LogHandler.h +++ b/libraries/shared/src/LogHandler.h @@ -19,6 +19,8 @@ #include #include +#include + const int VERBOSE_LOG_INTERVAL_SECONDS = 5; enum LogMsgType { @@ -34,6 +36,10 @@ class LogHandler : public QObject { Q_OBJECT public: static LogHandler& getInstance(); + + virtual ~LogHandler() { + std::cerr << "XXXXXXXX ~LogHandler()\n"; + } /// sets the target name to output via the verboseMessageHandler, called once before logging begins /// \param targetName the desired target name to output in logs From e985f56b122a883a767348aa0b911c5e915ab878 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 29 Apr 2015 15:30:13 -0700 Subject: [PATCH 08/13] cleanups --- assignment-client/src/AssignmentClient.cpp | 4 ---- assignment-client/src/AssignmentClientApp.cpp | 1 + .../src/octree/OctreeInboundPacketProcessor.h | 1 - assignment-client/src/octree/OctreeServer.cpp | 6 +----- assignment-client/src/octree/OctreeServer.h | 3 --- libraries/networking/src/LimitedNodeList.h | 4 ---- libraries/networking/src/NodeList.h | 5 ----- libraries/networking/src/ThreadedAssignment.cpp | 9 --------- libraries/networking/src/ThreadedAssignment.h | 1 - libraries/shared/src/DependencyManager.h | 10 +--------- libraries/shared/src/LogHandler.h | 6 ------ 11 files changed, 3 insertions(+), 47 deletions(-) diff --git a/assignment-client/src/AssignmentClient.cpp b/assignment-client/src/AssignmentClient.cpp index 4f00b30f42..594805c7c2 100644 --- a/assignment-client/src/AssignmentClient.cpp +++ b/assignment-client/src/AssignmentClient.cpp @@ -117,18 +117,14 @@ void AssignmentClient::stopAssignmentClient() { if (_currentAssignment) { _currentAssignment->aboutToQuit(); QThread* currentAssignmentThread = _currentAssignment->thread(); - qDebug() << "main thread waiting on _currentAssignment->thread()" << currentAssignmentThread->objectName(); currentAssignmentThread->quit(); currentAssignmentThread->wait(); - qDebug() << "done waiting."; } } void AssignmentClient::aboutToQuit() { - qDebug() << "AssignmentClient::aboutToQuit start"; stopAssignmentClient(); - qDebug() << "AssignmentClient::aboutToQuit end"; // clear the log handler so that Qt doesn't call the destructor on LogHandler qInstallMessageHandler(0); // clear out pointer to the assignment so the destructor gets called. if we don't do this here, diff --git a/assignment-client/src/AssignmentClientApp.cpp b/assignment-client/src/AssignmentClientApp.cpp index d8e4306ec5..2de349ca4e 100644 --- a/assignment-client/src/AssignmentClientApp.cpp +++ b/assignment-client/src/AssignmentClientApp.cpp @@ -167,6 +167,7 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) : } + if (parser.isSet(numChildsOption)) { if (minForks && minForks > numForks) { qCritical() << "--min can't be more than -n"; diff --git a/assignment-client/src/octree/OctreeInboundPacketProcessor.h b/assignment-client/src/octree/OctreeInboundPacketProcessor.h index 2f9c060183..156e09b493 100644 --- a/assignment-client/src/octree/OctreeInboundPacketProcessor.h +++ b/assignment-client/src/octree/OctreeInboundPacketProcessor.h @@ -74,7 +74,6 @@ public: NodeToSenderStatsMap& getSingleSenderStats() { return _singleSenderStats; } - // void shuttingDown() { _shuttingDown = true;} virtual void terminating() { _shuttingDown = true; ReceivedPacketProcessor::terminating(); } protected: diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index 11509192ad..f6f1c486b5 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -239,10 +239,8 @@ OctreeServer::OctreeServer(const QByteArray& packet) : _octreeInboundPacketProcessor(NULL), _persistThread(NULL), _started(time(0)), - _startedUSecs(usecTimestampNow()), - _nodeList(DependencyManager::get()) + _startedUSecs(usecTimestampNow()) { - if (_instance) { qDebug() << "Octree Server starting... while old instance still running _instance=["<<_instance<<"] this=[" << this << "]"; } @@ -1100,8 +1098,6 @@ void OctreeServer::readConfiguration() { } void OctreeServer::run() { - // qInstallMessageHandler(LogHandler::verboseMessageHandler); - _safeServerName = getMyServerName(); // Before we do anything else, create our tree... diff --git a/assignment-client/src/octree/OctreeServer.h b/assignment-client/src/octree/OctreeServer.h index 09368fbe4d..41cd3259cf 100644 --- a/assignment-client/src/octree/OctreeServer.h +++ b/assignment-client/src/octree/OctreeServer.h @@ -238,9 +238,6 @@ protected: static QMutex _threadsDidPacketDistributorMutex; static QMutex _threadsDidHandlePacketSendMutex; static QMutex _threadsDidCallWriteDatagramMutex; - - // keep a pointer to node list so that it doesn't get shut down before this class. - QSharedPointer _nodeList; }; #endif // hifi_OctreeServer_h diff --git a/libraries/networking/src/LimitedNodeList.h b/libraries/networking/src/LimitedNodeList.h index f541a29d01..a7057b4ed8 100644 --- a/libraries/networking/src/LimitedNodeList.h +++ b/libraries/networking/src/LimitedNodeList.h @@ -221,10 +221,6 @@ protected: LimitedNodeList(unsigned short socketListenPort = 0, unsigned short dtlsListenPort = 0); LimitedNodeList(LimitedNodeList const&); // Don't implement, needed to avoid copies of singleton void operator=(LimitedNodeList const&); // Don't implement, needed to avoid copies of singleton - - virtual ~LimitedNodeList() { - qDebug() << "XXXXXXXXXXXXXXXXXXXX ~LimitedNodeList called"; - } qint64 writeDatagram(const QByteArray& datagram, const HifiSockAddr& destinationSockAddr, const QUuid& connectionSecret); diff --git a/libraries/networking/src/NodeList.h b/libraries/networking/src/NodeList.h index 4cb3fb8ea2..ccfaa7a4cf 100644 --- a/libraries/networking/src/NodeList.h +++ b/libraries/networking/src/NodeList.h @@ -45,11 +45,6 @@ class NodeList : public LimitedNodeList { SINGLETON_DEPENDENCY public: - virtual ~NodeList() { - qDebug() << "XXXXXXXXXXXXXXXXXXXX ~NodeList called"; - } - - NodeType_t getOwnerType() const { return _ownerType; } void setOwnerType(NodeType_t ownerType) { _ownerType = ownerType; } diff --git a/libraries/networking/src/ThreadedAssignment.cpp b/libraries/networking/src/ThreadedAssignment.cpp index 6ec47d7cdd..eda3da8479 100644 --- a/libraries/networking/src/ThreadedAssignment.cpp +++ b/libraries/networking/src/ThreadedAssignment.cpp @@ -26,14 +26,7 @@ ThreadedAssignment::ThreadedAssignment(const QByteArray& packet) : } -ThreadedAssignment::~ThreadedAssignment() { - // setFinished(true); -} - void ThreadedAssignment::setFinished(bool isFinished) { - - qDebug() << "------------- ThreadedAssignment::setFinished" << isFinished << " -------------------"; - _isFinished = isFinished; if (_isFinished) { @@ -57,10 +50,8 @@ void ThreadedAssignment::setFinished(bool isFinished) { if (_datagramProcessingThread) { // tell the datagram processing thread to quit and wait until it is done, then return the node socket to the NodeList - qDebug() << "stopping datagramProcessingThread..."; _datagramProcessingThread->quit(); _datagramProcessingThread->wait(); - qDebug() << "done stopping datagramProcessingThread."; // set node socket parent back to NodeList nodeList->getNodeSocket().setParent(nodeList.data()); diff --git a/libraries/networking/src/ThreadedAssignment.h b/libraries/networking/src/ThreadedAssignment.h index e2c6e0a1b6..590c2f56ca 100644 --- a/libraries/networking/src/ThreadedAssignment.h +++ b/libraries/networking/src/ThreadedAssignment.h @@ -20,7 +20,6 @@ class ThreadedAssignment : public Assignment { Q_OBJECT public: ThreadedAssignment(const QByteArray& packet); - virtual ~ThreadedAssignment(); void setFinished(bool isFinished); virtual void aboutToFinish() { }; diff --git a/libraries/shared/src/DependencyManager.h b/libraries/shared/src/DependencyManager.h index 1d91872940..cdda72438a 100644 --- a/libraries/shared/src/DependencyManager.h +++ b/libraries/shared/src/DependencyManager.h @@ -26,12 +26,9 @@ class Dependency { public: typedef std::function DeleterFunction; - const QString& getDependencyName() { return _name; } protected: - virtual ~Dependency() { - qDebug() << "DESTRUCTING" << _name; - } + virtual ~Dependency() {} virtual void customDeleter() { _customDeleter(this); } @@ -39,9 +36,6 @@ protected: void setCustomDeleter(DeleterFunction customDeleter) { _customDeleter = customDeleter; } DeleterFunction _customDeleter = [](Dependency* pointer) { delete pointer; }; - void setDependencyName(QString name) { _name = name; } - QString _name; - friend class DependencyManager; }; @@ -101,7 +95,6 @@ QSharedPointer DependencyManager::set(Args&&... args) { QSharedPointer newInstance(new T(args...), &T::customDeleter); QSharedPointer storedInstance = qSharedPointerCast(newInstance); instance.swap(storedInstance); - newInstance->setDependencyName(typeid(T).name()); return newInstance; } @@ -109,7 +102,6 @@ QSharedPointer DependencyManager::set(Args&&... args) { template void DependencyManager::destroy() { static size_t hashCode = _manager.getHashCode(); - qDebug() << "DESTROYING" << _manager.safeGet(hashCode)->getDependencyName(); _manager.safeGet(hashCode).clear(); } diff --git a/libraries/shared/src/LogHandler.h b/libraries/shared/src/LogHandler.h index 1e9567b4d7..914cad212d 100644 --- a/libraries/shared/src/LogHandler.h +++ b/libraries/shared/src/LogHandler.h @@ -19,8 +19,6 @@ #include #include -#include - const int VERBOSE_LOG_INTERVAL_SECONDS = 5; enum LogMsgType { @@ -36,10 +34,6 @@ class LogHandler : public QObject { Q_OBJECT public: static LogHandler& getInstance(); - - virtual ~LogHandler() { - std::cerr << "XXXXXXXX ~LogHandler()\n"; - } /// sets the target name to output via the verboseMessageHandler, called once before logging begins /// \param targetName the desired target name to output in logs From 69766f6e595328052468ea4adf4e6b5879865c0d Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 29 Apr 2015 15:34:31 -0700 Subject: [PATCH 09/13] cleanups --- assignment-client/src/avatars/AvatarMixer.cpp | 5 ++--- libraries/shared/src/DependencyManager.h | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index 5612450f1f..6c8ba91f1b 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -45,7 +45,6 @@ AvatarMixer::AvatarMixer(const QByteArray& packet) : } AvatarMixer::~AvatarMixer() { - qDebug() << "AvatarMixer::~AvatarMixer"; if (_broadcastTimer) { _broadcastTimer->deleteLater(); } @@ -65,9 +64,9 @@ const float BILLBOARD_AND_IDENTITY_SEND_PROBABILITY = 1.0f / 300.0f; // 1) use the view frustum to cull those avatars that are out of view. Since avatar data doesn't need to be present // if the avatar is not in view or in the keyhole. void AvatarMixer::broadcastAvatarData() { - + int idleTime = QDateTime::currentMSecsSinceEpoch() - _lastFrameTimestamp; - + ++_numStatFrames; const float STRUGGLE_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD = 0.10f; diff --git a/libraries/shared/src/DependencyManager.h b/libraries/shared/src/DependencyManager.h index cdda72438a..01b755fdd0 100644 --- a/libraries/shared/src/DependencyManager.h +++ b/libraries/shared/src/DependencyManager.h @@ -35,7 +35,7 @@ protected: void setCustomDeleter(DeleterFunction customDeleter) { _customDeleter = customDeleter; } DeleterFunction _customDeleter = [](Dependency* pointer) { delete pointer; }; - + friend class DependencyManager; }; From b041fd1b7f53336ef937bbe9f02b3c406ffe8c04 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 29 Apr 2015 15:58:56 -0700 Subject: [PATCH 10/13] AssignmentClientMonitor now waits() on children --- .../src/AssignmentClientMonitor.cpp | 22 +++++++++++++++---- .../src/AssignmentClientMonitor.h | 4 +++- .../src/entities/EntityServer.cpp | 2 -- 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/assignment-client/src/AssignmentClientMonitor.cpp b/assignment-client/src/AssignmentClientMonitor.cpp index 31743ea630..df77e33ef0 100644 --- a/assignment-client/src/AssignmentClientMonitor.cpp +++ b/assignment-client/src/AssignmentClientMonitor.cpp @@ -69,6 +69,17 @@ AssignmentClientMonitor::~AssignmentClientMonitor() { stopChildProcesses(); } +void AssignmentClientMonitor::waitOnChildren(int msecs) { + QMutableListIterator i(_childProcesses); + while (i.hasNext()) { + QProcess* childProcess = i.next(); + bool finished = childProcess->waitForFinished(msecs); + if (finished) { + i.remove(); + } + } +} + void AssignmentClientMonitor::stopChildProcesses() { auto nodeList = DependencyManager::get(); @@ -78,8 +89,10 @@ void AssignmentClientMonitor::stopChildProcesses() { QByteArray diePacket = byteArrayWithPopulatedHeader(PacketTypeStopNode); nodeList->writeUnverifiedDatagram(diePacket, *node->getActiveSocket()); }); -} + // try to give all the children time to shutdown + waitOnChildren(15000); +} void AssignmentClientMonitor::aboutToQuit() { stopChildProcesses(); @@ -87,10 +100,11 @@ void AssignmentClientMonitor::aboutToQuit() { qInstallMessageHandler(0); } - void AssignmentClientMonitor::spawnChildClient() { QProcess *assignmentClient = new QProcess(this); + _childProcesses.append(assignmentClient); + // unparse the parts of the command-line that the child cares about QStringList _childArguments; if (_assignmentPool != "") { @@ -127,8 +141,6 @@ void AssignmentClientMonitor::spawnChildClient() { qDebug() << "Spawned a child client with PID" << assignmentClient->pid(); } - - void AssignmentClientMonitor::checkSpares() { auto nodeList = DependencyManager::get(); QUuid aSpareId = ""; @@ -164,6 +176,8 @@ void AssignmentClientMonitor::checkSpares() { nodeList->writeUnverifiedDatagram(diePacket, childNode); } } + + waitOnChildren(0); } diff --git a/assignment-client/src/AssignmentClientMonitor.h b/assignment-client/src/AssignmentClientMonitor.h index 23f50ef67d..e0129bd9b9 100644 --- a/assignment-client/src/AssignmentClientMonitor.h +++ b/assignment-client/src/AssignmentClientMonitor.h @@ -32,7 +32,8 @@ public: QString assignmentPool, QUuid walletUUID, QString assignmentServerHostname, quint16 assignmentServerPort); ~AssignmentClientMonitor(); - + + void waitOnChildren(int msecs); void stopChildProcesses(); private slots: void readPendingDatagrams(); @@ -55,6 +56,7 @@ private: QString _assignmentServerHostname; quint16 _assignmentServerPort; + QList _childProcesses; }; #endif // hifi_AssignmentClientMonitor_h diff --git a/assignment-client/src/entities/EntityServer.cpp b/assignment-client/src/entities/EntityServer.cpp index a175eef475..e202c17a7d 100644 --- a/assignment-client/src/entities/EntityServer.cpp +++ b/assignment-client/src/entities/EntityServer.cpp @@ -27,8 +27,6 @@ EntityServer::EntityServer(const QByteArray& packet) } EntityServer::~EntityServer() { - qDebug() << "EntityServer::~EntityServer"; - if (_pruneDeletedEntitiesTimer) { _pruneDeletedEntitiesTimer->stop(); _pruneDeletedEntitiesTimer->deleteLater(); From 0d2991b9b0e31f84d2ca59c494e8280bd6e93f9d Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 29 Apr 2015 16:24:36 -0700 Subject: [PATCH 11/13] Update edit.js to buffer mouseMove events This helps keep events from getting backed up on the event queue by handling move events in the update() loop and dropping extra move events that might come before an update. --- examples/edit.js | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/examples/edit.js b/examples/edit.js index 59dcbaad19..e6dd03de96 100644 --- a/examples/edit.js +++ b/examples/edit.js @@ -592,7 +592,11 @@ var idleMouseTimerId = null; var IDLE_MOUSE_TIMEOUT = 200; var DEFAULT_ENTITY_DRAG_DROP_DISTANCE = 2.0; -function mouseMoveEvent(event) { +var lastMouseMoveEvent = null; +function mouseMoveEventBuffered(event) { + lastMouseMoveEvent = event; +} +function mouseMove(event) { mouseHasMovedSincePress = true; if (placingEntityID) { @@ -661,6 +665,10 @@ function highlightEntityUnderCursor(position, accurateRay) { function mouseReleaseEvent(event) { + if (lastMouseMoveEvent) { + mouseMove(lastMouseMoveEvent); + lastMouseMoveEvent = null; + } if (propertyMenu.mouseReleaseEvent(event) || toolBar.mouseReleaseEvent(event)) { return true; } @@ -772,7 +780,7 @@ function mouseClickEvent(event) { } Controller.mousePressEvent.connect(mousePressEvent); -Controller.mouseMoveEvent.connect(mouseMoveEvent); +Controller.mouseMoveEvent.connect(mouseMoveEventBuffered); Controller.mouseReleaseEvent.connect(mouseReleaseEvent); @@ -882,6 +890,10 @@ Script.update.connect(function (deltaTime) { lastOrientation = Camera.orientation; lastPosition = Camera.position; } + if (lastMouseMoveEvent) { + mouseMove(lastMouseMoveEvent); + lastMouseMoveEvent = null; + } }); function insideBox(center, dimensions, point) { From 09eea83461ac8b8cfb2718b65c4fa686daa369a6 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 29 Apr 2015 19:18:58 -0700 Subject: [PATCH 12/13] don't give timers owners while also keeping track of them in as class instance variables --- assignment-client/src/entities/EntityServer.cpp | 2 +- libraries/networking/src/ThreadedAssignment.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/assignment-client/src/entities/EntityServer.cpp b/assignment-client/src/entities/EntityServer.cpp index e202c17a7d..bb5042f4b4 100644 --- a/assignment-client/src/entities/EntityServer.cpp +++ b/assignment-client/src/entities/EntityServer.cpp @@ -53,7 +53,7 @@ Octree* EntityServer::createTree() { } void EntityServer::beforeRun() { - _pruneDeletedEntitiesTimer = new QTimer(this); + _pruneDeletedEntitiesTimer = new QTimer(); connect(_pruneDeletedEntitiesTimer, SIGNAL(timeout()), this, SLOT(pruneDeletedEntities())); const int PRUNE_DELETED_MODELS_INTERVAL_MSECS = 1 * 1000; // once every second _pruneDeletedEntitiesTimer->start(PRUNE_DELETED_MODELS_INTERVAL_MSECS); diff --git a/libraries/networking/src/ThreadedAssignment.cpp b/libraries/networking/src/ThreadedAssignment.cpp index eda3da8479..43bcce4530 100644 --- a/libraries/networking/src/ThreadedAssignment.cpp +++ b/libraries/networking/src/ThreadedAssignment.cpp @@ -74,13 +74,13 @@ void ThreadedAssignment::commonInit(const QString& targetName, NodeType_t nodeTy // this is a temp fix for Qt 5.3 - rebinding the node socket gives us readyRead for the socket on this thread nodeList->rebindNodeSocket(); - _domainServerTimer = new QTimer(this); + _domainServerTimer = new QTimer(); connect(_domainServerTimer, SIGNAL(timeout()), this, SLOT(checkInWithDomainServerOrExit())); _domainServerTimer->start(DOMAIN_SERVER_CHECK_IN_MSECS); if (shouldSendStats) { // send a stats packet every 1 second - _statsTimer = new QTimer(this); + _statsTimer = new QTimer(); connect(_statsTimer, &QTimer::timeout, this, &ThreadedAssignment::sendStatsPacket); _statsTimer->start(1000); } From 2b9ec8b6bf4e369316e3288cdf1f95a9b15cd82a Mon Sep 17 00:00:00 2001 From: Eric Levin Date: Wed, 29 Apr 2015 22:13:26 -0700 Subject: [PATCH 13/13] fixed bug in grab.js where drop line overlay was not showing in correct position on first grab --- examples/grab.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/examples/grab.js b/examples/grab.js index eca457f0b2..4e0c536a1b 100644 --- a/examples/grab.js +++ b/examples/grab.js @@ -59,7 +59,13 @@ function mousePressEvent(event) { isGrabbing = true; savedGravity = props.gravity; Overlays.editOverlay(dropLine, { - visible: true + visible: true, + start: props.position, + end: Vec3.sum(props.position, { + x: 0, + y: -DROP_DISTANCE, + z: 0 + }) }); Entities.editEntity(grabbedEntity, { gravity: {