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