From 569ae113a03242ec31266ed87f79f87529b4467a Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Thu, 2 Feb 2017 16:19:21 +0000 Subject: [PATCH] memoize audio ignore box in AudioMixerClientData --- .../src/audio/AudioMixerClientData.cpp | 34 +++++++++++++++++++ .../src/audio/AudioMixerClientData.h | 15 +++++++- .../src/audio/AudioMixerSlave.cpp | 27 +++------------ 3 files changed, 52 insertions(+), 24 deletions(-) diff --git a/assignment-client/src/audio/AudioMixerClientData.cpp b/assignment-client/src/audio/AudioMixerClientData.cpp index 70d6a67b5b..216958a00d 100644 --- a/assignment-client/src/audio/AudioMixerClientData.cpp +++ b/assignment-client/src/audio/AudioMixerClientData.cpp @@ -59,6 +59,40 @@ AvatarAudioStream* AudioMixerClientData::getAvatarAudioStream() { return NULL; } +AABox& AudioMixerClientData::getIgnoreBox(unsigned int frame) { + // check for a memoized box + if (frame != _ignoreBoxMemo.frame.load(std::memory_order_acquire) { + // create the box + AABox box(getAvatarBoundingBoxCorner(), getAvatarBoundingBoxScale()); + + // enforce a minimum scale + static const glm::vec3 MIN_IGNORE_BOX_SCALE = glm::vec3(0.3f, 1.3f, 0.3f); + if (glm::any(glm::lessThan(getAvatarBoundingBoxScale(), MIN_IGNORE_BOX_SCALE))) { + box.setScaleStayCentered(MIN_IGNORE_BOX_SCALE); + } + + // quadruple the scale + const float IGNORE_BOX_SCALE_FACTOR = 4.0f; + box.embiggen(IGNORE_BOX_SCALE_FACTOR); + + // update the memoized box + // this may be called by multiple threads concurrently, + // so take a lock and only update the memo if this call is first. + // this prevents concurrent updates from invalidating the returned reference + // (contingent on the preconditions listed in the header). + std::lock_guard lock(_ignoreBoxMemo.mutex); + if (frame != _ignoreBoxMemo.frame.load(std::memory_order_acquire)) { + _ignoreBoxMemo.box = box; + unsigned int oldFrame = _ignoreBoxMemo.frame.exchange(frame, std::memory_order_release); + + // check the precondition + assert(frame == (oldFrame + 1)); + } + } + + return _ignoreBoxMemo.box; +} + void AudioMixerClientData::removeHRTFForStream(const QUuid& nodeID, const QUuid& streamID) { auto it = _nodeSourcesHRTFMap.find(nodeID); if (it != _nodeSourcesHRTFMap.end()) { diff --git a/assignment-client/src/audio/AudioMixerClientData.h b/assignment-client/src/audio/AudioMixerClientData.h index e637fd0409..1a4124ebff 100644 --- a/assignment-client/src/audio/AudioMixerClientData.h +++ b/assignment-client/src/audio/AudioMixerClientData.h @@ -38,6 +38,12 @@ public: AudioStreamMap getAudioStreams() { QReadLocker readLock { &_streamsLock }; return _audioStreams; } AvatarAudioStream* getAvatarAudioStream(); + // returns an ignore box, memoized by frame (lockless if the box is already memoized) + // preconditions: + // - frame is monotonically increasing + // - calls are only made to getIgnoreBox(frame + 1) when there are no references left from calls to getIgnoreBox(frame) + AABox& AudioMixerClientData::getIgnoreBox(unsigned int frame); + // the following methods should be called from the AudioMixer assignment thread ONLY // they are not thread-safe @@ -86,7 +92,7 @@ public: bool shouldFlushEncoder() { return _shouldFlushEncoder; } QString getCodecName() { return _selectedCodecName; } - + bool shouldMuteClient() { return _shouldMuteClient; } void setShouldMuteClient(bool shouldMuteClient) { _shouldMuteClient = shouldMuteClient; } glm::vec3 getPosition() { return getAvatarAudioStream() ? getAvatarAudioStream()->getPosition() : glm::vec3(0); } @@ -106,6 +112,13 @@ private: QReadWriteLock _streamsLock; AudioStreamMap _audioStreams; // microphone stream from avatar is stored under key of null UUID + struct IgnoreBoxMemo { + AABox box; + std::atomic frame { 0 }; + std::mutex mutex; + }; + IgnoreBoxMemo _ignoreBoxMemo; + using HRTFMap = std::unordered_map; using NodeSourcesHRTFMap = std::unordered_map; NodeSourcesHRTFMap _nodeSourcesHRTFMap; diff --git a/assignment-client/src/audio/AudioMixerSlave.cpp b/assignment-client/src/audio/AudioMixerSlave.cpp index adc6413316..fff8ef77bb 100644 --- a/assignment-client/src/audio/AudioMixerSlave.cpp +++ b/assignment-client/src/audio/AudioMixerSlave.cpp @@ -146,7 +146,7 @@ bool AudioMixerSlave::prepareMix(const SharedNodePointer& listener) { mixStream(*listenerData, node->getUUID(), *listenerAudioStream, *nodeStream); } } - } else if (!shouldIgnoreNode(listener, node)) { + } else if (!shouldIgnoreNode(listener, node, _frame)) { if (!isThrottling) { allStreams(node, &AudioMixerSlave::mixStream); } else { @@ -452,7 +452,7 @@ void sendEnvironmentPacket(const SharedNodePointer& node, AudioMixerClientData& } } -bool shouldIgnoreNode(const SharedNodePointer& listener, const SharedNodePointer& node) { +bool shouldIgnoreNode(const SharedNodePointer& listener, const SharedNodePointer& node, unsigned int frame) { AudioMixerClientData* listenerData = static_cast(listener->getLinkedData()); AudioMixerClientData* nodeData = static_cast(node->getLinkedData()); @@ -469,27 +469,8 @@ bool shouldIgnoreNode(const SharedNodePointer& listener, const SharedNodePointer // is either node enabling the space bubble / ignore radius? if ((listener->isIgnoreRadiusEnabled() || node->isIgnoreRadiusEnabled())) { - // define the minimum bubble size - static const glm::vec3 minBubbleSize = glm::vec3(0.3f, 1.3f, 0.3f); - - // set up the bounding box for the listener - AABox listenerBox(listenerData->getAvatarBoundingBoxCorner(), listenerData->getAvatarBoundingBoxScale()); - if (glm::any(glm::lessThan(listenerData->getAvatarBoundingBoxScale(), minBubbleSize))) { - listenerBox.setScaleStayCentered(minBubbleSize); - } - - // set up the bounding box for the node - AABox nodeBox(nodeData->getAvatarBoundingBoxCorner(), nodeData->getAvatarBoundingBoxScale()); - // Clamp the size of the bounding box to a minimum scale - if (glm::any(glm::lessThan(nodeData->getAvatarBoundingBoxScale(), minBubbleSize))) { - nodeBox.setScaleStayCentered(minBubbleSize); - } - - // quadruple the scale of both bounding boxes - listenerBox.embiggen(4.0f); - nodeBox.embiggen(4.0f); - - // perform the collision check between the two bounding boxes + AABox& listenerBox = listenerData->getIgnoreBox(frame); + AABox& nodeBox = nodeData->getIgnoreBox(frame); ignore = listenerBox.touches(nodeBox); } else { ignore = false;