diff --git a/assignment-client/src/audio/AudioMixerClientData.cpp b/assignment-client/src/audio/AudioMixerClientData.cpp index de7bdbc780..c51f240b54 100644 --- a/assignment-client/src/audio/AudioMixerClientData.cpp +++ b/assignment-client/src/audio/AudioMixerClientData.cpp @@ -113,6 +113,7 @@ void AudioMixerClientData::optionallyReplicatePacket(ReceivedMessage& message, c // first, make sure that this is a packet from a node we are supposed to replicate if (node.isReplicated()) { + auto nodeList = DependencyManager::get(); // now make sure it's a packet type that we want to replicate @@ -133,25 +134,25 @@ void AudioMixerClientData::optionallyReplicatePacket(ReceivedMessage& message, c std::unique_ptr packet; // enumerate the downstream audio mixers and send them the replicated version of this packet - nodeList->eachMatchingNode([&](const SharedNodePointer& node)->bool { - return node->getType() == NodeType::DownstreamAudioMixer; - }, [&](const SharedNodePointer& node) { - // construct the packet only once, if we have any downstream audio mixers to send to - if (!packet) { - // construct an NLPacket to send to the replicant that has the contents of the received packet - packet = NLPacket::create(mirroredType); + nodeList->unsafeEachNode([&](const SharedNodePointer& node) { + if (node->getType() == NodeType::DownstreamAudioMixer) { + // construct the packet only once, if we have any downstream audio mixers to send to + if (!packet) { + // construct an NLPacket to send to the replicant that has the contents of the received packet + packet = NLPacket::create(mirroredType); - // since this packet will be non-sourced, we add the replicated node's ID here - packet->write(message.getSourceID().toRfc4122()); + // since this packet will be non-sourced, we add the replicated node's ID here + packet->write(message.getSourceID().toRfc4122()); - // we won't negotiate an audio format with the replicant, because we aren't a listener - // so pack the codec string here so that it can statelessly setup a decoder for this string when it needs - packet->writeString(_selectedCodecName); + // we won't negotiate an audio format with the replicant, because we aren't a listener + // so pack the codec string here so that it can statelessly setup a decoder for this string when it needs + packet->writeString(_selectedCodecName); + + packet->write(message.getMessage()); + } - packet->write(message.getMessage()); + nodeList->sendUnreliablePacket(*packet, node->getPublicSocket()); } - - nodeList->sendUnreliablePacket(*packet, node->getPublicSocket()); }); } diff --git a/libraries/networking/src/LimitedNodeList.h b/libraries/networking/src/LimitedNodeList.h index 1ace6b2e23..5e2c88ed94 100644 --- a/libraries/networking/src/LimitedNodeList.h +++ b/libraries/networking/src/LimitedNodeList.h @@ -257,6 +257,16 @@ public: return SharedNodePointer(); } + // This is unsafe because it does not take a lock + // Must only be called when you know that a read lock on the node mutex is held + // and will be held for the duration of your iteration + template + void unsafeEachNode(NodeLambda functor) { + for (NodeHash::const_iterator it = _nodeHash.cbegin(); it != _nodeHash.cend(); ++it) { + functor(it->second); + } + } + void putLocalPortIntoSharedMemory(const QString key, QObject* parent, quint16 localPort); bool getLocalServerPortFromSharedMemory(const QString key, quint16& localPort);