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