memoize audio ignore box in AudioMixerClientData

This commit is contained in:
Zach Pomerantz 2017-02-02 16:19:21 +00:00
parent ff56eb24c8
commit 569ae113a0
3 changed files with 52 additions and 24 deletions

View file

@ -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()) {

View file

@ -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<unsigned int> frame { 0 };
std::mutex mutex;
};
IgnoreBoxMemo _ignoreBoxMemo;
using HRTFMap = std::unordered_map<QUuid, AudioHRTF>;
using NodeSourcesHRTFMap = std::unordered_map<QUuid, HRTFMap>;
NodeSourcesHRTFMap _nodeSourcesHRTFMap;

View file

@ -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<AudioMixerClientData*>(listener->getLinkedData());
AudioMixerClientData* nodeData = static_cast<AudioMixerClientData*>(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;