From 37c69ebe625000b61a95f79f95b21c09b9a22357 Mon Sep 17 00:00:00 2001 From: Clement Date: Mon, 5 Nov 2018 17:18:28 -0800 Subject: [PATCH 1/9] Add audio soloing feature --- assignment-client/src/audio/AudioMixer.cpp | 3 +- .../src/audio/AudioMixerClientData.cpp | 22 ++++++ .../src/audio/AudioMixerClientData.h | 6 ++ .../src/audio/AudioMixerSlave.cpp | 4 + libraries/audio-client/src/AudioClient.cpp | 8 +- libraries/audio-client/src/AudioClient.h | 4 +- libraries/audio/src/AbstractAudioInterface.h | 3 + libraries/audio/src/AudioSolo.cpp | 77 +++++++++++++++++++ libraries/audio/src/AudioSolo.h | 38 +++++++++ libraries/networking/src/udt/PacketHeaders.h | 3 +- .../src/AudioScriptingInterface.h | 22 +++++- 11 files changed, 183 insertions(+), 7 deletions(-) create mode 100644 libraries/audio/src/AudioSolo.cpp create mode 100644 libraries/audio/src/AudioSolo.h diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index afd4047c68..d6f893c42e 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -89,7 +89,8 @@ AudioMixer::AudioMixer(ReceivedMessage& message) : PacketType::NodeIgnoreRequest, PacketType::RadiusIgnoreRequest, PacketType::RequestsDomainListData, - PacketType::PerAvatarGainSet }, + PacketType::PerAvatarGainSet, + PacketType::AudioSoloRequest }, this, "queueAudioPacket"); // packets whose consequences are global should be processed on the main thread diff --git a/assignment-client/src/audio/AudioMixerClientData.cpp b/assignment-client/src/audio/AudioMixerClientData.cpp index 7e1420ef60..0aee185088 100644 --- a/assignment-client/src/audio/AudioMixerClientData.cpp +++ b/assignment-client/src/audio/AudioMixerClientData.cpp @@ -98,6 +98,9 @@ int AudioMixerClientData::processPackets(ConcurrentAddedStreams& addedStreams) { case PacketType::RadiusIgnoreRequest: parseRadiusIgnoreRequest(packet, node); break; + case PacketType::AudioSoloRequest: + parseSoloRequest(packet, node); + break; default: Q_UNREACHABLE(); } @@ -295,6 +298,25 @@ void AudioMixerClientData::parseRadiusIgnoreRequest(QSharedPointer message, const SharedNodePointer& node) { + + bool addToSolo; + message->readPrimitive(&addToSolo); + + while (message->getBytesLeftToRead()) { + // parse out the UUID being solod from the packet + QUuid solodUUID = QUuid::fromRfc4122(message->readWithoutCopy(NUM_BYTES_RFC4122_UUID)); + + if (addToSolo) { + _solodNodes.push_back(solodUUID); + } else { + auto it = std::find(std::begin(_solodNodes), std::end(_solodNodes), solodUUID); + _solodNodes.erase(it); + } + } +} + AvatarAudioStream* AudioMixerClientData::getAvatarAudioStream() { auto it = std::find_if(_audioStreams.begin(), _audioStreams.end(), [](const SharedStreamPointer& stream){ return stream->getStreamIdentifier().isNull(); diff --git a/assignment-client/src/audio/AudioMixerClientData.h b/assignment-client/src/audio/AudioMixerClientData.h index 610b258789..dd5681c537 100644 --- a/assignment-client/src/audio/AudioMixerClientData.h +++ b/assignment-client/src/audio/AudioMixerClientData.h @@ -65,6 +65,7 @@ public: void parsePerAvatarGainSet(ReceivedMessage& message, const SharedNodePointer& node); void parseNodeIgnoreRequest(QSharedPointer message, const SharedNodePointer& node); void parseRadiusIgnoreRequest(QSharedPointer message, const SharedNodePointer& node); + void parseSoloRequest(QSharedPointer message, const SharedNodePointer& node); // attempt to pop a frame from each audio stream, and return the number of streams from this client int checkBuffersBeforeFrameSend(); @@ -150,6 +151,9 @@ public: const Node::IgnoredNodeIDs& getIgnoringNodeIDs() const { return _ignoringNodeIDs; } + + const std::vector& getSolodNodes() const { return _solodNodes; } + bool getHasReceivedFirstMix() const { return _hasReceivedFirstMix; } void setHasReceivedFirstMix(bool hasReceivedFirstMix) { _hasReceivedFirstMix = hasReceivedFirstMix; } @@ -209,6 +213,8 @@ private: std::atomic_bool _isIgnoreRadiusEnabled { false }; + std::vector _solodNodes; + bool _hasReceivedFirstMix { false }; }; diff --git a/assignment-client/src/audio/AudioMixerSlave.cpp b/assignment-client/src/audio/AudioMixerSlave.cpp index 57bada47f1..7007e684cb 100644 --- a/assignment-client/src/audio/AudioMixerSlave.cpp +++ b/assignment-client/src/audio/AudioMixerSlave.cpp @@ -272,6 +272,10 @@ bool shouldBeSkipped(MixableStream& stream, const Node& listener, return true; } + if (!listenerData.getSolodNodes().empty()) { + return !contains(listenerData.getSolodNodes(), stream.nodeStreamID.nodeID); + } + bool shouldCheckIgnoreBox = (listenerAudioStream.isIgnoreBoxEnabled() || stream.positionalStream->isIgnoreBoxEnabled()); if (shouldCheckIgnoreBox && diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp index bdd6d0edc1..ace8f72875 100644 --- a/libraries/audio-client/src/AudioClient.cpp +++ b/libraries/audio-client/src/AudioClient.cpp @@ -270,7 +270,8 @@ AudioClient::AudioClient() : configureReverb(); - auto& packetReceiver = DependencyManager::get()->getPacketReceiver(); + auto nodeList = DependencyManager::get(); + auto& packetReceiver = nodeList->getPacketReceiver(); packetReceiver.registerListener(PacketType::AudioStreamStats, &_stats, "processStreamStatsPacket"); packetReceiver.registerListener(PacketType::AudioEnvironment, this, "handleAudioEnvironmentDataPacket"); packetReceiver.registerListener(PacketType::SilentAudioFrame, this, "handleAudioDataPacket"); @@ -278,6 +279,11 @@ AudioClient::AudioClient() : packetReceiver.registerListener(PacketType::NoisyMute, this, "handleNoisyMutePacket"); packetReceiver.registerListener(PacketType::MuteEnvironment, this, "handleMuteEnvironmentPacket"); packetReceiver.registerListener(PacketType::SelectedAudioFormat, this, "handleSelectedAudioFormat"); + + auto& domainHandler = nodeList->getDomainHandler(); + connect(&domainHandler, &DomainHandler::disconnectedFromDomain, this, [this] { + _solo.reset(); + }); } AudioClient::~AudioClient() { diff --git a/libraries/audio-client/src/AudioClient.h b/libraries/audio-client/src/AudioClient.h index 5e7f1fb8a0..751bddd35d 100644 --- a/libraries/audio-client/src/AudioClient.h +++ b/libraries/audio-client/src/AudioClient.h @@ -46,7 +46,6 @@ #include #include - #include #include @@ -171,6 +170,7 @@ public: void stopRecording(); void setAudioPaused(bool pause); + AudioSolo& getAudioSolo() override { return _solo; } #ifdef Q_OS_WIN static QString getWinDeviceName(wchar_t* guid); @@ -446,6 +446,8 @@ private: #if defined(Q_OS_ANDROID) bool _shouldRestartInputSetup { true }; // Should we restart the input device because of an unintended stop? #endif + + AudioSolo _solo; Mutex _checkDevicesMutex; QTimer* _checkDevicesTimer { nullptr }; diff --git a/libraries/audio/src/AbstractAudioInterface.h b/libraries/audio/src/AbstractAudioInterface.h index bbfd79d0aa..0f075ab224 100644 --- a/libraries/audio/src/AbstractAudioInterface.h +++ b/libraries/audio/src/AbstractAudioInterface.h @@ -19,6 +19,7 @@ #include "AudioInjectorOptions.h" #include "AudioInjector.h" +#include "AudioSolo.h" class AudioInjector; class AudioInjectorLocalBuffer; @@ -38,6 +39,8 @@ public: // take care to delete it when ~AudioInjector, as parenting Qt semantics will not work virtual bool outputLocalInjector(const AudioInjectorPointer& injector) = 0; + virtual AudioSolo& getAudioSolo() = 0; + public slots: virtual bool shouldLoopbackInjectors() { return false; } diff --git a/libraries/audio/src/AudioSolo.cpp b/libraries/audio/src/AudioSolo.cpp new file mode 100644 index 0000000000..306c728dcb --- /dev/null +++ b/libraries/audio/src/AudioSolo.cpp @@ -0,0 +1,77 @@ +// +// AudioSolo.cpp +// +// +// Created by Clement Brisset on 11/5/18. +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "AudioSolo.h" + +#include + +bool AudioSolo::isSoloing() const { + Lock lock(_mutex); + return !_nodesSoloed.empty(); +} + +QVector AudioSolo::getUUIDs() const { + Lock lock(_mutex); + return _nodesSoloed.values().toVector(); +} + +void AudioSolo::addUUIDs(QVector uuidList) { + // create a reliable NLPacket with space for the solo UUIDs + auto soloPacket = NLPacket::create(PacketType::AudioSoloRequest, + uuidList.size() * NUM_BYTES_RFC4122_UUID + sizeof(bool), true); + soloPacket->writePrimitive(true); + + { + Lock lock(_mutex); + for (auto uuid : uuidList) { + if (_nodesSoloed.contains(uuid)) { + qWarning() << "Uuid already in solo list:" << uuid; + } else { + // write the node ID to the packet + soloPacket->write(uuid.toRfc4122()); + _nodesSoloed.insert(uuid); + } + } + } + + // send off this ignore packet reliably to the matching node + auto nodeList = DependencyManager::get(); + nodeList->broadcastToNodes(std::move(soloPacket), { NodeType::AudioMixer }); +} + +void AudioSolo::removeUUIDs(QVector uuidList) { + // create a reliable NLPacket with space for the solo UUIDs + auto soloPacket = NLPacket::create(PacketType::AudioSoloRequest, + uuidList.size() * NUM_BYTES_RFC4122_UUID + sizeof(bool), true); + soloPacket->writePrimitive(false); + + { + Lock lock(_mutex); + for (auto uuid : uuidList) { + if (!_nodesSoloed.contains(uuid)) { + qWarning() << "Uuid not in solo list:" << uuid; + } else { + // write the node ID to the packet + soloPacket->write(uuid.toRfc4122()); + _nodesSoloed.remove(uuid); + } + } + } + + // send off this ignore packet reliably to the matching node + auto nodeList = DependencyManager::get(); + nodeList->broadcastToNodes(std::move(soloPacket), { NodeType::AudioMixer }); +} + +void AudioSolo::reset() { + removeUUIDs(getUUIDs()); +} + diff --git a/libraries/audio/src/AudioSolo.h b/libraries/audio/src/AudioSolo.h new file mode 100644 index 0000000000..ef2d2d0bec --- /dev/null +++ b/libraries/audio/src/AudioSolo.h @@ -0,0 +1,38 @@ +// +// AudioSolo.h +// libraries/audio/src +// +// Created by Clement Brisset on 11/5/18. +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#pragma once + +#ifndef hifi_AudioSolo_h +#define hifi_AudioSolo_h + +#include + +#include +#include + +class AudioSolo { + using Mutex = std::mutex; + using Lock = std::unique_lock; + +public: + bool isSoloing() const; + QVector getUUIDs() const; + void addUUIDs(QVector uuidList); + void removeUUIDs(QVector uuidList); + void reset(); + +private: + mutable Mutex _mutex; + QSet _nodesSoloed; +}; + +#endif // hifi_AudioSolo_h diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index 37a4b32940..e5efe05ad0 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -126,14 +126,13 @@ public: EntityScriptCallMethod, ChallengeOwnershipRequest, ChallengeOwnershipReply, - OctreeDataFileRequest, OctreeDataFileReply, OctreeDataPersist, - EntityClone, EntityQueryInitialResultsComplete, BulkAvatarTraits, + AudioSoloRequest, NUM_PACKET_TYPE }; diff --git a/libraries/script-engine/src/AudioScriptingInterface.h b/libraries/script-engine/src/AudioScriptingInterface.h index 1220a9b769..7808a86566 100644 --- a/libraries/script-engine/src/AudioScriptingInterface.h +++ b/libraries/script-engine/src/AudioScriptingInterface.h @@ -25,13 +25,31 @@ class AudioScriptingInterface : public QObject, public Dependency { // JSDoc for property is in Audio.h. Q_PROPERTY(bool isStereoInput READ isStereoInput WRITE setStereoInput NOTIFY isStereoInputChanged) + Q_PROPERTY(bool isSoloing READ isSoloing) + Q_PROPERTY(QVector soloList READ getSoloList) public: - virtual ~AudioScriptingInterface() {} + virtual ~AudioScriptingInterface() = default; void setLocalAudioInterface(AbstractAudioInterface* audioInterface); protected: - AudioScriptingInterface() {} + AudioScriptingInterface() = default; + + bool isSoloing() const { + return _localAudioInterface->getAudioSolo().isSoloing(); + } + QVector getSoloList() const { + return _localAudioInterface->getAudioSolo().getUUIDs(); + } + Q_INVOKABLE void addToSoloList(QVector uuidList) { + _localAudioInterface->getAudioSolo().addUUIDs(uuidList); + } + Q_INVOKABLE void removeFromSoloList(QVector uuidList) { + _localAudioInterface->getAudioSolo().removeUUIDs(uuidList); + } + Q_INVOKABLE void resetSoloList() { + _localAudioInterface->getAudioSolo().reset(); + } // these methods are protected to stop C++ callers from calling, but invokable from script From 4e802b0f3fd83f553e667a8d04c10e92e9f4df30 Mon Sep 17 00:00:00 2001 From: Clement Date: Tue, 6 Nov 2018 11:59:15 -0800 Subject: [PATCH 2/9] Add JSDoc comments --- interface/src/scripting/Audio.h | 2 ++ .../src/AudioScriptingInterface.h | 24 ++++++++++++++++--- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/interface/src/scripting/Audio.h b/interface/src/scripting/Audio.h index 4b8eb6aabc..738eeb5dfe 100644 --- a/interface/src/scripting/Audio.h +++ b/interface/src/scripting/Audio.h @@ -50,6 +50,8 @@ class Audio : public AudioScriptingInterface, protected ReadWriteLockable { * Read-only. * @property {object} devices Read-only. Deprecated: This property is deprecated and will be * removed. + * @property {boolean} isSoloing Read-only. true if any nodes are soloed. + * @property {QVector} soloList Read-only. Get the list of currently soloed node UUIDs. */ Q_PROPERTY(bool muted READ isMuted WRITE setMuted NOTIFY mutedChanged) diff --git a/libraries/script-engine/src/AudioScriptingInterface.h b/libraries/script-engine/src/AudioScriptingInterface.h index 7808a86566..ba570fd7c0 100644 --- a/libraries/script-engine/src/AudioScriptingInterface.h +++ b/libraries/script-engine/src/AudioScriptingInterface.h @@ -32,25 +32,43 @@ public: virtual ~AudioScriptingInterface() = default; void setLocalAudioInterface(AbstractAudioInterface* audioInterface); -protected: - AudioScriptingInterface() = default; - bool isSoloing() const { return _localAudioInterface->getAudioSolo().isSoloing(); } + QVector getSoloList() const { return _localAudioInterface->getAudioSolo().getUUIDs(); } + + /**jsdoc + * Add nodes to the audio solo list + * @function Audio.addToSoloList + * @param {QVector} uuidList - List of node UUIDs to add to the solo list. + */ Q_INVOKABLE void addToSoloList(QVector uuidList) { _localAudioInterface->getAudioSolo().addUUIDs(uuidList); } + + /**jsdoc + * Remove nodes from the audio solo list + * @function Audio.removeFromSoloList + * @param {QVector} uuidList - List of node UUIDs to remove from the solo list. + */ Q_INVOKABLE void removeFromSoloList(QVector uuidList) { _localAudioInterface->getAudioSolo().removeUUIDs(uuidList); } + + /**jsdoc + * Reset the list of soloed nodes. + * @function Audio.resetSoloList + */ Q_INVOKABLE void resetSoloList() { _localAudioInterface->getAudioSolo().reset(); } +protected: + AudioScriptingInterface() = default; + // these methods are protected to stop C++ callers from calling, but invokable from script /**jsdoc From 0ca0a6f3bebc44c192e1038d5220546945a52ca2 Mon Sep 17 00:00:00 2001 From: Clement Date: Tue, 6 Nov 2018 12:56:51 -0800 Subject: [PATCH 3/9] Fix JSDoc arrays --- interface/src/scripting/Audio.h | 2 +- libraries/script-engine/src/AudioScriptingInterface.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/interface/src/scripting/Audio.h b/interface/src/scripting/Audio.h index 738eeb5dfe..4c4bf6dd60 100644 --- a/interface/src/scripting/Audio.h +++ b/interface/src/scripting/Audio.h @@ -51,7 +51,7 @@ class Audio : public AudioScriptingInterface, protected ReadWriteLockable { * @property {object} devices Read-only. Deprecated: This property is deprecated and will be * removed. * @property {boolean} isSoloing Read-only. true if any nodes are soloed. - * @property {QVector} soloList Read-only. Get the list of currently soloed node UUIDs. + * @property {Uuid[]} soloList Read-only. Get the list of currently soloed node UUIDs. */ Q_PROPERTY(bool muted READ isMuted WRITE setMuted NOTIFY mutedChanged) diff --git a/libraries/script-engine/src/AudioScriptingInterface.h b/libraries/script-engine/src/AudioScriptingInterface.h index ba570fd7c0..2854445b4f 100644 --- a/libraries/script-engine/src/AudioScriptingInterface.h +++ b/libraries/script-engine/src/AudioScriptingInterface.h @@ -43,7 +43,7 @@ public: /**jsdoc * Add nodes to the audio solo list * @function Audio.addToSoloList - * @param {QVector} uuidList - List of node UUIDs to add to the solo list. + * @param {Uuid[]} uuidList - List of node UUIDs to add to the solo list. */ Q_INVOKABLE void addToSoloList(QVector uuidList) { _localAudioInterface->getAudioSolo().addUUIDs(uuidList); @@ -52,7 +52,7 @@ public: /**jsdoc * Remove nodes from the audio solo list * @function Audio.removeFromSoloList - * @param {QVector} uuidList - List of node UUIDs to remove from the solo list. + * @param {Uuid[]} uuidList - List of node UUIDs to remove from the solo list. */ Q_INVOKABLE void removeFromSoloList(QVector uuidList) { _localAudioInterface->getAudioSolo().removeUUIDs(uuidList); From beb575a88d3a20c18c3884860bc48052d5de90ae Mon Sep 17 00:00:00 2001 From: Clement Date: Tue, 6 Nov 2018 13:18:26 -0800 Subject: [PATCH 4/9] Don't attenuate soloed nodes. --- assignment-client/src/audio/AudioMixerSlave.cpp | 17 ++++++++++++----- assignment-client/src/audio/AudioMixerSlave.h | 2 +- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/assignment-client/src/audio/AudioMixerSlave.cpp b/assignment-client/src/audio/AudioMixerSlave.cpp index 7007e684cb..0308acc697 100644 --- a/assignment-client/src/audio/AudioMixerSlave.cpp +++ b/assignment-client/src/audio/AudioMixerSlave.cpp @@ -314,6 +314,7 @@ bool AudioMixerSlave::prepareMix(const SharedNodePointer& listener) { memset(_mixSamples, 0, sizeof(_mixSamples)); bool isThrottling = _numToRetain != -1; + bool isSoloing = !listenerData->getSolodNodes().empty(); auto& streams = listenerData->getStreams(); @@ -380,13 +381,14 @@ bool AudioMixerSlave::prepareMix(const SharedNodePointer& listener) { stream.approximateVolume = approximateVolume(stream, listenerAudioStream); } else { if (shouldBeSkipped(stream, *listener, *listenerAudioStream, *listenerData)) { - addStream(stream, *listenerAudioStream, 0.0f); + addStream(stream, *listenerAudioStream, 0.0f, isSoloing); streams.skipped.push_back(move(stream)); ++stats.activeToSkipped; return true; } - addStream(stream, *listenerAudioStream, listenerData->getMasterAvatarGain()); + addStream(stream, *listenerAudioStream, listenerData->getMasterAvatarGain(), + isSoloing); if (shouldBeInactive(stream)) { // To reduce artifacts we still call render to flush the HRTF for every silent @@ -421,7 +423,8 @@ bool AudioMixerSlave::prepareMix(const SharedNodePointer& listener) { return true; } - addStream(stream, *listenerAudioStream, listenerData->getMasterAvatarGain()); + addStream(stream, *listenerAudioStream, listenerData->getMasterAvatarGain(), + isSoloing); if (shouldBeInactive(stream)) { // To reduce artifacts we still call render to flush the HRTF for every silent @@ -488,7 +491,7 @@ bool AudioMixerSlave::prepareMix(const SharedNodePointer& listener) { void AudioMixerSlave::addStream(AudioMixerClientData::MixableStream& mixableStream, AvatarAudioStream& listeningNodeStream, - float masterListenerGain) { + float masterListenerGain, bool isSoloing) { ++stats.totalMixes; auto streamToAdd = mixableStream.positionalStream; @@ -499,9 +502,13 @@ void AudioMixerSlave::addStream(AudioMixerClientData::MixableStream& mixableStre glm::vec3 relativePosition = streamToAdd->getPosition() - listeningNodeStream.getPosition(); float distance = glm::max(glm::length(relativePosition), EPSILON); - float gain = computeGain(masterListenerGain, listeningNodeStream, *streamToAdd, relativePosition, distance, isEcho); float azimuth = isEcho ? 0.0f : computeAzimuth(listeningNodeStream, listeningNodeStream, relativePosition); + float gain = 1.0f; + if (!isSoloing) { + gain = computeGain(masterListenerGain, listeningNodeStream, *streamToAdd, relativePosition, distance, isEcho); + } + const int HRTF_DATASET_INDEX = 1; if (!streamToAdd->lastPopSucceeded()) { diff --git a/assignment-client/src/audio/AudioMixerSlave.h b/assignment-client/src/audio/AudioMixerSlave.h index 6566c839b8..3d979da1fc 100644 --- a/assignment-client/src/audio/AudioMixerSlave.h +++ b/assignment-client/src/audio/AudioMixerSlave.h @@ -57,7 +57,7 @@ private: bool prepareMix(const SharedNodePointer& listener); void addStream(AudioMixerClientData::MixableStream& mixableStream, AvatarAudioStream& listeningNodeStream, - float masterListenerGain); + float masterListenerGain, bool isSoloing); void updateHRTFParameters(AudioMixerClientData::MixableStream& mixableStream, AvatarAudioStream& listeningNodeStream, float masterListenerGain); From b8cb433fa13b0127572a9b4e6dbe8a03c3d188d6 Mon Sep 17 00:00:00 2001 From: Clement Date: Tue, 6 Nov 2018 13:20:03 -0800 Subject: [PATCH 5/9] Spelling --- assignment-client/src/audio/AudioMixerClientData.cpp | 10 +++++----- assignment-client/src/audio/AudioMixerClientData.h | 4 ++-- assignment-client/src/audio/AudioMixerSlave.cpp | 6 +++--- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/assignment-client/src/audio/AudioMixerClientData.cpp b/assignment-client/src/audio/AudioMixerClientData.cpp index 0aee185088..3b47b058e7 100644 --- a/assignment-client/src/audio/AudioMixerClientData.cpp +++ b/assignment-client/src/audio/AudioMixerClientData.cpp @@ -305,14 +305,14 @@ void AudioMixerClientData::parseSoloRequest(QSharedPointer mess message->readPrimitive(&addToSolo); while (message->getBytesLeftToRead()) { - // parse out the UUID being solod from the packet - QUuid solodUUID = QUuid::fromRfc4122(message->readWithoutCopy(NUM_BYTES_RFC4122_UUID)); + // parse out the UUID being soloed from the packet + QUuid soloedUUID = QUuid::fromRfc4122(message->readWithoutCopy(NUM_BYTES_RFC4122_UUID)); if (addToSolo) { - _solodNodes.push_back(solodUUID); + _soloedNodes.push_back(soloedUUID); } else { - auto it = std::find(std::begin(_solodNodes), std::end(_solodNodes), solodUUID); - _solodNodes.erase(it); + auto it = std::find(std::begin(_soloedNodes), std::end(_soloedNodes), soloedUUID); + _soloedNodes.erase(it); } } } diff --git a/assignment-client/src/audio/AudioMixerClientData.h b/assignment-client/src/audio/AudioMixerClientData.h index dd5681c537..0232fe6bb6 100644 --- a/assignment-client/src/audio/AudioMixerClientData.h +++ b/assignment-client/src/audio/AudioMixerClientData.h @@ -152,7 +152,7 @@ public: const Node::IgnoredNodeIDs& getIgnoringNodeIDs() const { return _ignoringNodeIDs; } - const std::vector& getSolodNodes() const { return _solodNodes; } + const std::vector& getSoloedNodes() const { return _soloedNodes; } bool getHasReceivedFirstMix() const { return _hasReceivedFirstMix; } void setHasReceivedFirstMix(bool hasReceivedFirstMix) { _hasReceivedFirstMix = hasReceivedFirstMix; } @@ -213,7 +213,7 @@ private: std::atomic_bool _isIgnoreRadiusEnabled { false }; - std::vector _solodNodes; + std::vector _soloedNodes; bool _hasReceivedFirstMix { false }; }; diff --git a/assignment-client/src/audio/AudioMixerSlave.cpp b/assignment-client/src/audio/AudioMixerSlave.cpp index 0308acc697..7a6ab9c3e2 100644 --- a/assignment-client/src/audio/AudioMixerSlave.cpp +++ b/assignment-client/src/audio/AudioMixerSlave.cpp @@ -272,8 +272,8 @@ bool shouldBeSkipped(MixableStream& stream, const Node& listener, return true; } - if (!listenerData.getSolodNodes().empty()) { - return !contains(listenerData.getSolodNodes(), stream.nodeStreamID.nodeID); + if (!listenerData.getSoloedNodes().empty()) { + return !contains(listenerData.getSoloedNodes(), stream.nodeStreamID.nodeID); } bool shouldCheckIgnoreBox = (listenerAudioStream.isIgnoreBoxEnabled() || @@ -314,7 +314,7 @@ bool AudioMixerSlave::prepareMix(const SharedNodePointer& listener) { memset(_mixSamples, 0, sizeof(_mixSamples)); bool isThrottling = _numToRetain != -1; - bool isSoloing = !listenerData->getSolodNodes().empty(); + bool isSoloing = !listenerData->getSoloedNodes().empty(); auto& streams = listenerData->getStreams(); From 65a83cb026b6b04210e1203b7b82b13eb7cda8c9 Mon Sep 17 00:00:00 2001 From: Clement Date: Wed, 7 Nov 2018 11:41:04 -0800 Subject: [PATCH 6/9] Resend solo nodes on mixer reconnect --- libraries/audio-client/src/AudioClient.cpp | 5 +++++ libraries/audio/src/AudioSolo.cpp | 9 +++++++++ libraries/audio/src/AudioSolo.h | 4 +++- 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp index ace8f72875..8bc211cf9a 100644 --- a/libraries/audio-client/src/AudioClient.cpp +++ b/libraries/audio-client/src/AudioClient.cpp @@ -284,6 +284,11 @@ AudioClient::AudioClient() : connect(&domainHandler, &DomainHandler::disconnectedFromDomain, this, [this] { _solo.reset(); }); + connect(nodeList.data(), &NodeList::nodeAdded, this, [this](SharedNodePointer node) { + if (node->getType() == NodeType::AudioMixer) { + _solo.resend(); + } + }); } AudioClient::~AudioClient() { diff --git a/libraries/audio/src/AudioSolo.cpp b/libraries/audio/src/AudioSolo.cpp index 306c728dcb..83ecc6e130 100644 --- a/libraries/audio/src/AudioSolo.cpp +++ b/libraries/audio/src/AudioSolo.cpp @@ -72,6 +72,15 @@ void AudioSolo::removeUUIDs(QVector uuidList) { } void AudioSolo::reset() { + Lock lock(_mutex); removeUUIDs(getUUIDs()); } + +void AudioSolo::resend() { + Lock lock(_mutex); + auto uuids = getUUIDs(); + _nodesSoloed.clear(); + addUUIDs(uuids); +} + diff --git a/libraries/audio/src/AudioSolo.h b/libraries/audio/src/AudioSolo.h index ef2d2d0bec..790280a14b 100644 --- a/libraries/audio/src/AudioSolo.h +++ b/libraries/audio/src/AudioSolo.h @@ -20,7 +20,7 @@ #include class AudioSolo { - using Mutex = std::mutex; + using Mutex = std::recursive_mutex; using Lock = std::unique_lock; public: @@ -30,6 +30,8 @@ public: void removeUUIDs(QVector uuidList); void reset(); + void resend(); + private: mutable Mutex _mutex; QSet _nodesSoloed; From 8f763dfd5036384ca496b67a50d897b639191679 Mon Sep 17 00:00:00 2001 From: Clement Date: Wed, 7 Nov 2018 17:44:48 -0800 Subject: [PATCH 7/9] Fix bug and crash in solo logic --- assignment-client/src/audio/AudioMixerClientData.cpp | 4 ++-- libraries/audio-client/src/AudioClient.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/assignment-client/src/audio/AudioMixerClientData.cpp b/assignment-client/src/audio/AudioMixerClientData.cpp index 3b47b058e7..68727a16be 100644 --- a/assignment-client/src/audio/AudioMixerClientData.cpp +++ b/assignment-client/src/audio/AudioMixerClientData.cpp @@ -311,8 +311,8 @@ void AudioMixerClientData::parseSoloRequest(QSharedPointer mess if (addToSolo) { _soloedNodes.push_back(soloedUUID); } else { - auto it = std::find(std::begin(_soloedNodes), std::end(_soloedNodes), soloedUUID); - _soloedNodes.erase(it); + auto it = std::remove(std::begin(_soloedNodes), std::end(_soloedNodes), soloedUUID); + _soloedNodes.erase(it, std::end(_soloedNodes)); } } } diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp index 8bc211cf9a..cab02e215e 100644 --- a/libraries/audio-client/src/AudioClient.cpp +++ b/libraries/audio-client/src/AudioClient.cpp @@ -284,7 +284,7 @@ AudioClient::AudioClient() : connect(&domainHandler, &DomainHandler::disconnectedFromDomain, this, [this] { _solo.reset(); }); - connect(nodeList.data(), &NodeList::nodeAdded, this, [this](SharedNodePointer node) { + connect(nodeList.data(), &NodeList::nodeActivated, this, [this](SharedNodePointer node) { if (node->getType() == NodeType::AudioMixer) { _solo.resend(); } From ef54a63de622f5362d9ae763a22614b7c7b35a95 Mon Sep 17 00:00:00 2001 From: Clement Date: Wed, 7 Nov 2018 17:54:49 -0800 Subject: [PATCH 8/9] Use uint8_t instead of bool on the wire --- .../src/audio/AudioMixerClientData.cpp | 2 +- libraries/audio/src/AudioSolo.cpp | 14 ++++++++------ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/assignment-client/src/audio/AudioMixerClientData.cpp b/assignment-client/src/audio/AudioMixerClientData.cpp index 68727a16be..a7edd3169c 100644 --- a/assignment-client/src/audio/AudioMixerClientData.cpp +++ b/assignment-client/src/audio/AudioMixerClientData.cpp @@ -301,7 +301,7 @@ void AudioMixerClientData::parseRadiusIgnoreRequest(QSharedPointer message, const SharedNodePointer& node) { - bool addToSolo; + uint8_t addToSolo; message->readPrimitive(&addToSolo); while (message->getBytesLeftToRead()) { diff --git a/libraries/audio/src/AudioSolo.cpp b/libraries/audio/src/AudioSolo.cpp index 83ecc6e130..3302636096 100644 --- a/libraries/audio/src/AudioSolo.cpp +++ b/libraries/audio/src/AudioSolo.cpp @@ -26,8 +26,9 @@ QVector AudioSolo::getUUIDs() const { void AudioSolo::addUUIDs(QVector uuidList) { // create a reliable NLPacket with space for the solo UUIDs auto soloPacket = NLPacket::create(PacketType::AudioSoloRequest, - uuidList.size() * NUM_BYTES_RFC4122_UUID + sizeof(bool), true); - soloPacket->writePrimitive(true); + uuidList.size() * NUM_BYTES_RFC4122_UUID + sizeof(uint8_t), true); + uint8_t addToSoloList = (uint8_t)true; + soloPacket->writePrimitive(addToSoloList); { Lock lock(_mutex); @@ -42,7 +43,7 @@ void AudioSolo::addUUIDs(QVector uuidList) { } } - // send off this ignore packet reliably to the matching node + // send off this solo packet reliably to the matching node auto nodeList = DependencyManager::get(); nodeList->broadcastToNodes(std::move(soloPacket), { NodeType::AudioMixer }); } @@ -50,8 +51,9 @@ void AudioSolo::addUUIDs(QVector uuidList) { void AudioSolo::removeUUIDs(QVector uuidList) { // create a reliable NLPacket with space for the solo UUIDs auto soloPacket = NLPacket::create(PacketType::AudioSoloRequest, - uuidList.size() * NUM_BYTES_RFC4122_UUID + sizeof(bool), true); - soloPacket->writePrimitive(false); + uuidList.size() * NUM_BYTES_RFC4122_UUID + sizeof(uint8_t), true); + uint8_t addToSoloList = (uint8_t)false; + soloPacket->writePrimitive(addToSoloList); { Lock lock(_mutex); @@ -66,7 +68,7 @@ void AudioSolo::removeUUIDs(QVector uuidList) { } } - // send off this ignore packet reliably to the matching node + // send off this solo packet reliably to the matching node auto nodeList = DependencyManager::get(); nodeList->broadcastToNodes(std::move(soloPacket), { NodeType::AudioMixer }); } From f337579616edfcd7a77606e5b7c09305d8cf7d2a Mon Sep 17 00:00:00 2001 From: Clement Date: Thu, 8 Nov 2018 11:31:22 -0800 Subject: [PATCH 9/9] CR --- libraries/audio/src/AudioSolo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/audio/src/AudioSolo.cpp b/libraries/audio/src/AudioSolo.cpp index 3302636096..9d63f01a8b 100644 --- a/libraries/audio/src/AudioSolo.cpp +++ b/libraries/audio/src/AudioSolo.cpp @@ -1,6 +1,6 @@ // // AudioSolo.cpp -// +// libraries/audio/src // // Created by Clement Brisset on 11/5/18. // Copyright 2018 High Fidelity, Inc.