AudioMixerClientData::IgnoreZone& AudioMixerClientData::IgnoreZoneMemo::get(unsigned int frame) { // check for a memoized zone if (frame != _frame.load(std::memory_order_acquire)) { AvatarAudioStream* stream = _data.getAvatarAudioStream(); // get the initial dimensions from the stream glm::vec3 corner = stream ? stream->getAvatarBoundingBoxCorner() : glm::vec3(0); glm::vec3 scale = stream ? stream->getAvatarBoundingBoxScale() : glm::vec3(0); // 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(scale, MIN_IGNORE_BOX_SCALE))) { scale = MIN_IGNORE_BOX_SCALE; } // quadruple the scale (this is arbitrary number chosen for comfort) const float IGNORE_BOX_SCALE_FACTOR = 4.0f; scale *= IGNORE_BOX_SCALE_FACTOR; // create the box (we use a box for the zone for convenience) AABox box(corner, scale); // update the memoized zone // 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<std::mutex> lock(_mutex); if (frame != _frame.load(std::memory_order_acquire)) { _zone = box; unsigned int oldFrame = _frame.exchange(frame, std::memory_order_release); Q_UNUSED(oldFrame); } } return _zone; }