1 // Copyright 2005-2019 The Mumble Developers. All rights reserved.
2 // Use of this source code is governed by a BSD-style license
3 // that can be found in the LICENSE file at the root of the
4 // Mumble source tree or at <https://www.mumble.info/LICENSE>.
5
6 #include "mumble_pch.hpp"
7
8 #include "Audio.h"
9
10 #include "AudioInput.h"
11 #include "AudioOutput.h"
12 #include "CELTCodec.h"
13 #include "OpusCodec.h"
14 #include "Global.h"
15 #include "PacketDataStream.h"
16
17 class CodecInit : public DeferInit {
18 public:
19 void initialize();
20 void destroy();
21 };
22
23 #define DOUBLE_RAND (rand()/static_cast<double>(RAND_MAX))
24
25 LoopUser LoopUser::lpLoopy;
26 CodecInit ciInit;
27
initialize()28 void CodecInit::initialize() {
29 #ifdef USE_OPUS
30 OpusCodec *oCodec = new OpusCodec();
31 if (oCodec->isValid()) {
32 oCodec->report();
33 g.oCodec = oCodec;
34 } else {
35 qWarning("CodecInit: Failed to load Opus, it will not be available for encoding/decoding audio.");
36 delete oCodec;
37 }
38 #endif
39
40 if (g.s.bDisableCELT) {
41 // Kill switch for CELT activated. Do not initialize it.
42 return;
43 }
44
45 CELTCodec *codec = NULL;
46
47 #ifdef USE_SBCELT
48 codec = new CELTCodecSBCELT();
49 if (codec->isValid()) {
50 codec->report();
51 g.qmCodecs.insert(codec->bitstreamVersion(), codec);
52 } else {
53 delete codec;
54 }
55 #else
56 codec = new CELTCodec070(QLatin1String("0.7.0"));
57 if (codec->isValid()) {
58 codec->report();
59 g.qmCodecs.insert(codec->bitstreamVersion(), codec);
60 } else {
61 delete codec;
62 codec = new CELTCodec070(QLatin1String("0.0.0"));
63 if (codec->isValid()) {
64 codec->report();
65 g.qmCodecs.insert(codec->bitstreamVersion(), codec);
66 } else {
67 delete codec;
68 }
69 }
70
71 codec = new CELTCodec011(QLatin1String("0.11.0"));
72 if (codec->isValid()) {
73 codec->report();
74 g.qmCodecs.insert(codec->bitstreamVersion(), codec);
75 } else {
76 delete codec;
77 codec = new CELTCodec011(QLatin1String("2.0.0"));
78 if (codec->isValid()) {
79 codec->report();
80 g.qmCodecs.insert(codec->bitstreamVersion(), codec);
81 } else {
82 delete codec;
83 }
84 }
85 #endif
86 }
87
destroy()88 void CodecInit::destroy() {
89 #ifdef USE_OPUS
90 delete g.oCodec;
91 #endif
92
93 foreach(CELTCodec *codec, g.qmCodecs)
94 delete codec;
95 g.qmCodecs.clear();
96 }
97
LoopUser()98 LoopUser::LoopUser() {
99 qsName = QLatin1String("Loopy");
100 uiSession = 0;
101 iId = 0;
102 bMute = bDeaf = bSuppress = false;
103 bLocalIgnore = bLocalMute = bSelfDeaf = false;
104 tsState = Settings::Passive;
105 cChannel = NULL;
106 qtTicker.start();
107 qtLastFetch.start();
108 }
109
addFrame(const QByteArray & packet)110 void LoopUser::addFrame(const QByteArray &packet) {
111 if (DOUBLE_RAND < g.s.dPacketLoss) {
112 qWarning("Drop");
113 return;
114 }
115
116 {
117 QMutexLocker l(&qmLock);
118 bool restart = (qtLastFetch.elapsed() > 100);
119
120 double time = qtTicker.elapsed();
121
122 double r;
123 if (restart)
124 r = 0.0;
125 else
126 r = DOUBLE_RAND * g.s.dMaxPacketDelay;
127
128 qmPackets.insert(static_cast<float>(time + r), packet);
129 }
130
131 // Restart check
132 if (qtLastFetch.elapsed() > 100) {
133 AudioOutputPtr ao = g.ao;
134 if (ao) {
135 MessageHandler::UDPMessageType msgType = static_cast<MessageHandler::UDPMessageType>((packet.at(0) >> 5) & 0x7);
136 ao->addFrameToBuffer(this, QByteArray(), 0, msgType);
137 }
138 }
139
140 }
141
fetchFrames()142 void LoopUser::fetchFrames() {
143 QMutexLocker l(&qmLock);
144
145 AudioOutputPtr ao(g.ao);
146 if (!ao || qmPackets.isEmpty()) {
147 return;
148 }
149
150 double cmp = qtTicker.elapsed();
151
152 QMultiMap<float, QByteArray>::iterator i = qmPackets.begin();
153
154 while (i != qmPackets.end()) {
155 if (i.key() > cmp)
156 break;
157
158 int iSeq;
159 const QByteArray &data = i.value();
160 PacketDataStream pds(data.constData(), data.size());
161
162 unsigned int msgFlags = static_cast<unsigned int>(pds.next());
163
164 pds >> iSeq;
165
166 QByteArray qba;
167 qba.reserve(pds.left() + 1);
168 qba.append(static_cast<char>(msgFlags));
169 qba.append(pds.dataBlock(pds.left()));
170
171 MessageHandler::UDPMessageType msgType = static_cast<MessageHandler::UDPMessageType>((msgFlags >> 5) & 0x7);
172
173 ao->addFrameToBuffer(this, qba, iSeq, msgType);
174 i = qmPackets.erase(i);
175 }
176
177 qtLastFetch.restart();
178 }
179
RecordUser()180 RecordUser::RecordUser() : LoopUser() {
181 qsName = QLatin1String("Recorder");
182 }
183
~RecordUser()184 RecordUser::~RecordUser() {
185 AudioOutputPtr ao = g.ao;
186 if (ao)
187 ao->removeBuffer(this);
188 }
189
addFrame(const QByteArray & packet)190 void RecordUser::addFrame(const QByteArray &packet) {
191 AudioOutputPtr ao(g.ao);
192 if (!ao)
193 return;
194
195 int iSeq;
196 PacketDataStream pds(packet.constData(), packet.size());
197
198 unsigned int msgFlags = static_cast<unsigned int>(pds.next());
199
200 pds >> iSeq;
201
202 QByteArray qba;
203 qba.reserve(pds.left() + 1);
204 qba.append(static_cast<char>(msgFlags));
205 qba.append(pds.dataBlock(pds.left()));
206
207 MessageHandler::UDPMessageType msgType = static_cast<MessageHandler::UDPMessageType>((msgFlags >> 5) & 0x7);
208
209 ao->addFrameToBuffer(this, qba, iSeq, msgType);
210 }
211
startOutput(const QString & output)212 void Audio::startOutput(const QString &output) {
213 g.ao = AudioOutputRegistrar::newFromChoice(output);
214 if (g.ao)
215 g.ao->start(QThread::HighPriority);
216 }
217
stopOutput()218 void Audio::stopOutput() {
219 // Take a copy of the global AudioOutput shared pointer
220 // to keep a reference around.
221 AudioOutputPtr ao = g.ao;
222
223 // Reset the global AudioOutput shared pointer to the null pointer.
224 g.ao.reset();
225
226 // Wait until our copy of the AudioOutput shared pointer (ao)
227 // is the only one left.
228 while (ao.get() && ! ao.unique()) {
229 QThread::yieldCurrentThread();
230 }
231
232 // Reset our copy of the AudioOutput shared pointer.
233 // This causes the AudioOutput destructor to be called
234 // right here in this function, on the main thread.
235 // Our audio backends expect this to happen.
236 //
237 // One such example is PulseAudioInput, whose destructor
238 // takes the PulseAudio mainloop lock. If the destructor
239 // is called inside one of the PulseAudio callbacks that
240 // take copies of g.ai, the destructor will try to also
241 // take the mainloop lock, causing an abort().
242 ao.reset();
243 }
244
startInput(const QString & input)245 void Audio::startInput(const QString &input) {
246 g.ai = AudioInputRegistrar::newFromChoice(input);
247 if (g.ai)
248 g.ai->start(QThread::HighestPriority);
249 }
250
stopInput()251 void Audio::stopInput() {
252 // Take a copy of the global AudioInput shared pointer
253 // to keep a reference around.
254 AudioInputPtr ai = g.ai;
255
256 // Reset the global AudioInput shared pointer to the null pointer.
257 g.ai.reset();
258
259 // Wait until our copy of the AudioInput shared pointer (ai)
260 // is the only one left.
261 while (ai.get() && ! ai.unique()) {
262 QThread::yieldCurrentThread();
263 }
264
265 // Reset our copy of the AudioInput shared pointer.
266 // This causes the AudioInput destructor to be called
267 // right here in this function, on the main thread.
268 // Our audio backends expect this to happen.
269 //
270 // One such example is PulseAudioInput, whose destructor
271 // takes the PulseAudio mainloop lock. If the destructor
272 // is called inside one of the PulseAudio callbacks that
273 // take copies of g.ai, the destructor will try to also
274 // take the mainloop lock, causing an abort().
275 ai.reset();
276 }
277
start(const QString & input,const QString & output)278 void Audio::start(const QString &input, const QString &output) {
279 startInput(input);
280 startOutput(output);
281 }
282
stop()283 void Audio::stop() {
284 // Take copies of the global AudioInput and AudioOutput
285 // shared pointers to keep a reference to each of them
286 // around.
287 AudioInputPtr ai = g.ai;
288 AudioOutputPtr ao = g.ao;
289
290 // Reset the global AudioInput and AudioOutput shared pointers
291 // to the null pointer.
292 g.ao.reset();
293 g.ai.reset();
294
295 // Wait until our copies of the AudioInput and AudioOutput shared pointers
296 // (ai and ao) are the only ones left.
297 while ((ai.get() && ! ai.unique()) || (ao.get() && ! ao.unique())) {
298 QThread::yieldCurrentThread();
299 }
300
301 // Reset our copies of the AudioInput and AudioOutput
302 // shared pointers.
303 // This causes the AudioInput and AudioOutput destructors
304 // to be called right here in this function, on the main
305 // thread. Our audio backends expect this to happen.
306 //
307 // One such example is PulseAudioInput, whose destructor
308 // takes the PulseAudio mainloop lock. If the destructor
309 // is called inside one of the PulseAudio callbacks that
310 // take copies of g.ai, the destructor will try to also
311 // take the mainloop lock, causing an abort().
312 ai.reset();
313 ao.reset();
314 }
315