Overte C++ Documentation
AudioMixerClientData.h
1 //
2 // AudioMixerClientData.h
3 // assignment-client/src/audio
4 //
5 // Created by Stephen Birarda on 10/18/13.
6 // Copyright 2013 High Fidelity, Inc.
7 //
8 // Distributed under the Apache License, Version 2.0.
9 // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
10 //
11 
12 #ifndef hifi_AudioMixerClientData_h
13 #define hifi_AudioMixerClientData_h
14 
15 #include <queue>
16 
17 #if !defined(Q_MOC_RUN)
18 // Work around https://bugreports.qt.io/browse/QTBUG-80990
19 #include <tbb/concurrent_vector.h>
20 #endif
21 
22 #include <QtCore/QJsonObject>
23 #include <QtCore/QSharedPointer>
24 
25 #include <AABox.h>
26 #include <AudioHRTF.h>
27 #include <AudioLimiter.h>
28 #include <UUIDHasher.h>
29 
30 #include <plugins/Forward.h>
31 #include <plugins/CodecPlugin.h>
32 
33 #include "PositionalAudioStream.h"
34 #include "AvatarAudioStream.h"
35 
36 class AudioMixerClientData : public NodeData {
37  Q_OBJECT
38 public:
39  struct AddedStream {
40  NodeIDStreamID nodeIDStreamID;
41  PositionalAudioStream* positionalStream;
42 
43  AddedStream(QUuid nodeID, Node::LocalID localNodeID,
44  StreamID streamID, PositionalAudioStream* positionalStream) :
45  nodeIDStreamID(nodeID, localNodeID, streamID), positionalStream(positionalStream) {};
46  };
47 
48  using ConcurrentAddedStreams = tbb::concurrent_vector<AddedStream>;
49 
50  AudioMixerClientData(const QUuid& nodeID, Node::LocalID nodeLocalID);
51  ~AudioMixerClientData();
52 
53  using SharedStreamPointer = std::shared_ptr<PositionalAudioStream>;
54  using AudioStreamVector = std::vector<SharedStreamPointer>;
55 
56  void queuePacket(QSharedPointer<ReceivedMessage> packet, SharedNodePointer node);
57  int processPackets(ConcurrentAddedStreams& addedStreams); // returns the number of available streams this frame
58 
59  AudioStreamVector& getAudioStreams() { return _audioStreams; }
60  AvatarAudioStream* getAvatarAudioStream();
61 
62  void removeAgentAvatarAudioStream();
63 
64  // packet parsers
65  int parseData(ReceivedMessage& message) override;
66  void processStreamPacket(ReceivedMessage& message, ConcurrentAddedStreams& addedStreams);
67  void negotiateAudioFormat(ReceivedMessage& message, const SharedNodePointer& node);
68  void parseRequestsDomainListData(ReceivedMessage& message);
69  void parsePerAvatarGainSet(ReceivedMessage& message, const SharedNodePointer& node);
70  void parseInjectorGainSet(ReceivedMessage& message, const SharedNodePointer& node);
71  void parseNodeIgnoreRequest(QSharedPointer<ReceivedMessage> message, const SharedNodePointer& node);
72  void parseRadiusIgnoreRequest(QSharedPointer<ReceivedMessage> message, const SharedNodePointer& node);
73  void parseSoloRequest(QSharedPointer<ReceivedMessage> message, const SharedNodePointer& node);
74  void parseStopInjectorPacket(QSharedPointer<ReceivedMessage> packet);
75 
76  // attempt to pop a frame from each audio stream, and return the number of streams from this client
77  int checkBuffersBeforeFrameSend();
78 
79  QJsonObject getAudioStreamStats();
80 
81  void sendAudioStreamStatsPackets(const SharedNodePointer& destinationNode);
82 
83  void incrementOutgoingMixedAudioSequenceNumber() { _outgoingMixedAudioSequenceNumber++; }
84  quint16 getOutgoingSequenceNumber() const { return _outgoingMixedAudioSequenceNumber; }
85 
86  // uses randomization to have the AudioMixer send a stats packet to this node around every second
87  bool shouldSendStats(int frameNumber);
88 
89  float getMasterAvatarGain() const { return _masterAvatarGain; }
90  void setMasterAvatarGain(float gain) { _masterAvatarGain = gain; }
91  float getMasterInjectorGain() const { return _masterInjectorGain; }
92  void setMasterInjectorGain(float gain) { _masterInjectorGain = gain; }
93 
94  AudioLimiter audioLimiter;
95 
96  void setupCodec(CodecPluginPointer codec, const QString& codecName);
97  void cleanupCodec();
98  void encode(const QByteArray& decodedBuffer, QByteArray& encodedBuffer) {
99  if (_encoder) {
100  _encoder->encode(decodedBuffer, encodedBuffer);
101  } else {
102  encodedBuffer = decodedBuffer;
103  }
104  // once you have encoded, you need to flush eventually.
105  _shouldFlushEncoder = true;
106  }
107  void encodeFrameOfZeros(QByteArray& encodedZeros);
108  bool shouldFlushEncoder() { return _shouldFlushEncoder; }
109 
110  QString getCodecName() { return _selectedCodecName; }
111 
112  bool shouldMuteClient() { return _shouldMuteClient; }
113  void setShouldMuteClient(bool shouldMuteClient) { _shouldMuteClient = shouldMuteClient; }
114  glm::vec3 getPosition() { return getAvatarAudioStream() ? getAvatarAudioStream()->getPosition() : glm::vec3(0); }
115  bool getRequestsDomainListData() const { return _requestsDomainListData; }
116  void setRequestsDomainListData(bool requesting) { _requestsDomainListData = requesting; }
117 
118  void setupCodecForReplicatedAgent(QSharedPointer<ReceivedMessage> message);
119 
120  struct MixableStream {
121  float approximateVolume { 0.0f };
122  NodeIDStreamID nodeStreamID;
123  std::unique_ptr<AudioHRTF> hrtf;
124  PositionalAudioStream* positionalStream;
125  bool ignoredByListener { false };
126  bool ignoringListener { false };
127 
128  MixableStream(NodeIDStreamID nodeIDStreamID, PositionalAudioStream* positionalStream) :
129  nodeStreamID(nodeIDStreamID), hrtf(new AudioHRTF), positionalStream(positionalStream) {};
130  MixableStream(QUuid nodeID, Node::LocalID localNodeID, StreamID streamID, PositionalAudioStream* positionalStream) :
131  nodeStreamID(nodeID, localNodeID, streamID), hrtf(new AudioHRTF), positionalStream(positionalStream) {};
132  };
133 
134  using MixableStreamsVector = std::vector<MixableStream>;
135  struct Streams {
136  MixableStreamsVector active;
137  MixableStreamsVector inactive;
138  MixableStreamsVector skipped;
139  };
140 
141  Streams& getStreams() { return _streams; }
142 
143  // thread-safe, called from AudioMixerSlave(s) while processing ignore packets for other nodes
144  void ignoredByNode(QUuid nodeID);
145  void unignoredByNode(QUuid nodeID);
146 
147  // start of methods called non-concurrently from single AudioMixerSlave mixing for the owning node
148 
149  const Node::IgnoredNodeIDs& getNewIgnoredNodeIDs() const { return _newIgnoredNodeIDs; }
150  const Node::IgnoredNodeIDs& getNewUnignoredNodeIDs() const { return _newUnignoredNodeIDs; }
151 
152  using ConcurrentIgnoreNodeIDs = tbb::concurrent_vector<QUuid>;
153  const ConcurrentIgnoreNodeIDs& getNewIgnoringNodeIDs() const { return _newIgnoringNodeIDs; }
154  const ConcurrentIgnoreNodeIDs& getNewUnignoringNodeIDs() const { return _newUnignoringNodeIDs; }
155 
156  void clearStagedIgnoreChanges();
157 
158  const Node::IgnoredNodeIDs& getIgnoringNodeIDs() const { return _ignoringNodeIDs; }
159 
160 
161  const std::vector<QUuid>& getSoloedNodes() const { return _soloedNodes; }
162 
163  bool getHasReceivedFirstMix() const { return _hasReceivedFirstMix; }
164  void setHasReceivedFirstMix(bool hasReceivedFirstMix) { _hasReceivedFirstMix = hasReceivedFirstMix; }
165 
166  // end of methods called non-concurrently from single AudioMixerSlave
167 
168 signals:
169  void injectorStreamFinished(const QUuid& streamID);
170 
171 public slots:
172  void handleMismatchAudioFormat(SharedNodePointer node, const QString& currentCodec, const QString& recievedCodec);
173  void sendSelectAudioFormat(SharedNodePointer node, const QString& selectedCodecName);
174 
175 private:
176  struct PacketQueue : public std::queue<QSharedPointer<ReceivedMessage>> {
177  QWeakPointer<Node> node;
178  };
179  PacketQueue _packetQueue;
180 
181  AudioStreamVector _audioStreams; // microphone stream from avatar has a null stream ID
182 
183  void optionallyReplicatePacket(ReceivedMessage& packet, const Node& node);
184 
185  void setGainForAvatar(QUuid nodeID, float gain);
186 
187  bool containsValidPosition(ReceivedMessage& message) const;
188 
189  Streams _streams;
190 
191  quint16 _outgoingMixedAudioSequenceNumber;
192 
193  AudioStreamStats _downstreamAudioStreamStats;
194 
195  int _frameToSendStats { 0 };
196 
197  float _masterAvatarGain { 1.0f }; // per-listener mixing gain, applied only to avatars
198  float _masterInjectorGain { 1.0f }; // per-listener mixing gain, applied only to injectors
199 
200  CodecPluginPointer _codec;
201  QString _selectedCodecName;
202  Encoder* _encoder{ nullptr }; // for outbound mixed stream
203  Decoder* _decoder{ nullptr }; // for mic stream
204 
205  bool _shouldFlushEncoder { false };
206 
207  bool _shouldMuteClient { false };
208  bool _requestsDomainListData { false };
209 
210  std::vector<AddedStream> _newAddedStreams;
211 
212  Node::IgnoredNodeIDs _newIgnoredNodeIDs;
213  Node::IgnoredNodeIDs _newUnignoredNodeIDs;
214 
215  tbb::concurrent_vector<QUuid> _newIgnoringNodeIDs;
216  tbb::concurrent_vector<QUuid> _newUnignoringNodeIDs;
217 
218  std::mutex _ignoringNodeIDsMutex;
219  Node::IgnoredNodeIDs _ignoringNodeIDs;
220 
221  std::atomic_bool _isIgnoreRadiusEnabled { false };
222 
223  std::vector<QUuid> _soloedNodes;
224 
225  bool _hasReceivedFirstMix { false };
226 };
227 
228 #endif // hifi_AudioMixerClientData_h