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; 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) { void AudioMixerClientData::removeHRTFForStream(const QUuid& nodeID, const QUuid& streamID) {
auto it = _nodeSourcesHRTFMap.find(nodeID); auto it = _nodeSourcesHRTFMap.find(nodeID);
if (it != _nodeSourcesHRTFMap.end()) { if (it != _nodeSourcesHRTFMap.end()) {

View file

@ -38,6 +38,12 @@ public:
AudioStreamMap getAudioStreams() { QReadLocker readLock { &_streamsLock }; return _audioStreams; } AudioStreamMap getAudioStreams() { QReadLocker readLock { &_streamsLock }; return _audioStreams; }
AvatarAudioStream* getAvatarAudioStream(); 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 // the following methods should be called from the AudioMixer assignment thread ONLY
// they are not thread-safe // they are not thread-safe
@ -86,7 +92,7 @@ public:
bool shouldFlushEncoder() { return _shouldFlushEncoder; } bool shouldFlushEncoder() { return _shouldFlushEncoder; }
QString getCodecName() { return _selectedCodecName; } QString getCodecName() { return _selectedCodecName; }
bool shouldMuteClient() { return _shouldMuteClient; } bool shouldMuteClient() { return _shouldMuteClient; }
void setShouldMuteClient(bool shouldMuteClient) { _shouldMuteClient = shouldMuteClient; } void setShouldMuteClient(bool shouldMuteClient) { _shouldMuteClient = shouldMuteClient; }
glm::vec3 getPosition() { return getAvatarAudioStream() ? getAvatarAudioStream()->getPosition() : glm::vec3(0); } glm::vec3 getPosition() { return getAvatarAudioStream() ? getAvatarAudioStream()->getPosition() : glm::vec3(0); }
@ -106,6 +112,13 @@ private:
QReadWriteLock _streamsLock; QReadWriteLock _streamsLock;
AudioStreamMap _audioStreams; // microphone stream from avatar is stored under key of null UUID 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 HRTFMap = std::unordered_map<QUuid, AudioHRTF>;
using NodeSourcesHRTFMap = std::unordered_map<QUuid, HRTFMap>; using NodeSourcesHRTFMap = std::unordered_map<QUuid, HRTFMap>;
NodeSourcesHRTFMap _nodeSourcesHRTFMap; NodeSourcesHRTFMap _nodeSourcesHRTFMap;

View file

@ -146,7 +146,7 @@ bool AudioMixerSlave::prepareMix(const SharedNodePointer& listener) {
mixStream(*listenerData, node->getUUID(), *listenerAudioStream, *nodeStream); mixStream(*listenerData, node->getUUID(), *listenerAudioStream, *nodeStream);
} }
} }
} else if (!shouldIgnoreNode(listener, node)) { } else if (!shouldIgnoreNode(listener, node, _frame)) {
if (!isThrottling) { if (!isThrottling) {
allStreams(node, &AudioMixerSlave::mixStream); allStreams(node, &AudioMixerSlave::mixStream);
} else { } 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* listenerData = static_cast<AudioMixerClientData*>(listener->getLinkedData());
AudioMixerClientData* nodeData = static_cast<AudioMixerClientData*>(node->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? // is either node enabling the space bubble / ignore radius?
if ((listener->isIgnoreRadiusEnabled() || node->isIgnoreRadiusEnabled())) { if ((listener->isIgnoreRadiusEnabled() || node->isIgnoreRadiusEnabled())) {
// define the minimum bubble size AABox& listenerBox = listenerData->getIgnoreBox(frame);
static const glm::vec3 minBubbleSize = glm::vec3(0.3f, 1.3f, 0.3f); AABox& nodeBox = nodeData->getIgnoreBox(frame);
// 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
ignore = listenerBox.touches(nodeBox); ignore = listenerBox.touches(nodeBox);
} else { } else {
ignore = false; ignore = false;