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 "PulseAudio.h"
9 
10 #include "MainWindow.h"
11 #include "Timer.h"
12 #include "User.h"
13 
14 // We define a global macro called 'g'. This can lead to issues when included code uses 'g' as a type or parameter name (like protobuf 3.7 does). As such, for now, we have to make this our last include.
15 #include "Global.h"
16 
17 static const char *mumble_sink_input = "Mumble Speakers";
18 static const char *mumble_echo = "Mumble Speakers (Echo)";
19 
20 static PulseAudioSystem *pasys = NULL;
21 
22 #define NBLOCKS 8
23 
24 class PulseAudioInputRegistrar : public AudioInputRegistrar {
25 	public:
26 		PulseAudioInputRegistrar();
27 		virtual AudioInput *create();
28 		virtual const QList<audioDevice> getDeviceChoices();
29 		virtual void setDeviceChoice(const QVariant &, Settings &);
30 		virtual bool canEcho(const QString &) const;
31 };
32 
33 
34 class PulseAudioOutputRegistrar : public AudioOutputRegistrar {
35 	public:
36 		PulseAudioOutputRegistrar();
37 		virtual AudioOutput *create();
38 		virtual const QList<audioDevice> getDeviceChoices();
39 		virtual void setDeviceChoice(const QVariant &, Settings &);
40 		bool canMuteOthers() const;
41 };
42 
43 class PulseAudioInit : public DeferInit {
44 	public:
45 		PulseAudioInputRegistrar *airPulseAudio;
46 		PulseAudioOutputRegistrar *aorPulseAudio;
initialize()47 		void initialize() {
48 			pasys = new PulseAudioSystem();
49 			pasys->qmWait.lock();
50 			pasys->qwcWait.wait(&pasys->qmWait, 1000);
51 			pasys->qmWait.unlock();
52 			if (pasys->bPulseIsGood) {
53 				airPulseAudio = new PulseAudioInputRegistrar();
54 				aorPulseAudio = new PulseAudioOutputRegistrar();
55 			} else {
56 				airPulseAudio = NULL;
57 				aorPulseAudio = NULL;
58 				delete pasys;
59 				pasys = NULL;
60 			}
61 		};
destroy()62 		void destroy() {
63 			delete airPulseAudio;
64 			delete aorPulseAudio;
65 			delete pasys;
66 			pasys = NULL;
67 		};
68 };
69 
70 static PulseAudioInit pulseinit;
71 
PulseAudioSystem()72 PulseAudioSystem::PulseAudioSystem() {
73 	pasInput = pasOutput = pasSpeaker = NULL;
74 	bSourceDone=bSinkDone=bServerDone = false;
75 	iDelayCache = 0;
76 	bPositionalCache = false;
77 	bAttenuating = false;
78 	iRemainingOperations = 0;
79 	bPulseIsGood = false;
80 	iSinkId = -1;
81 
82 	pam = pa_threaded_mainloop_new();
83 	pa_mainloop_api *api = pa_threaded_mainloop_get_api(pam);
84 
85 	pa_proplist *proplist;
86 
87 	proplist = pa_proplist_new();
88 	pa_proplist_sets(proplist, PA_PROP_APPLICATION_NAME, "Mumble");
89 	pa_proplist_sets(proplist, PA_PROP_APPLICATION_ID, "net.sourceforge.mumble.mumble");
90 	pa_proplist_sets(proplist, PA_PROP_APPLICATION_ICON_NAME, "mumble");
91 	pa_proplist_sets(proplist, PA_PROP_MEDIA_ROLE, "game");
92 
93 	pacContext = pa_context_new_with_proplist(api, NULL, proplist);
94 	pa_proplist_free(proplist);
95 
96 	pa_context_set_subscribe_callback(pacContext, subscribe_callback, this);
97 
98 	pa_context_set_state_callback(pacContext, context_state_callback, this);
99 	pa_context_connect(pacContext, NULL, PA_CONTEXT_NOAUTOSPAWN, NULL);
100 
101 	pade = api->defer_new(api, defer_event_callback, this);
102 	api->defer_enable(pade, false);
103 
104 	pa_threaded_mainloop_start(pam);
105 
106 	bRunning = true;
107 }
108 
~PulseAudioSystem()109 PulseAudioSystem::~PulseAudioSystem() {
110 	bRunning = false;
111 	if (bAttenuating) {
112 		qmWait.lock();
113 		bAttenuating = false;
114 		setVolumes();
115 		bool success = qwcWait.wait(&qmWait, 1000);
116 		if (! success) {
117 			qWarning("PulseAudio: Shutdown timeout when attempting to restore volumes.");
118 		}
119 		qmWait.unlock();
120 	}
121 	pa_threaded_mainloop_stop(pam);
122 	pa_context_disconnect(pacContext);
123 	pa_context_unref(pacContext);
124 	pa_threaded_mainloop_free(pam);
125 }
126 
outputDevice() const127 QString PulseAudioSystem::outputDevice() const {
128 	QString odev = g.s.qsPulseAudioOutput;
129 	if (odev.isEmpty()) {
130 		odev = qsDefaultOutput;
131 	}
132 	if (!qhOutput.contains(odev)) {
133 		odev = qsDefaultOutput;
134 	}
135 	return odev;
136 }
137 
inputDevice() const138 QString PulseAudioSystem::inputDevice() const {
139 	QString idev = g.s.qsPulseAudioInput;
140 	if (idev.isEmpty()) {
141 		idev = qsDefaultInput;
142 	}
143 	if (!qhInput.contains(idev)) {
144 		idev = qsDefaultInput;
145 	}
146 	return idev;
147 }
148 
wakeup()149 void PulseAudioSystem::wakeup() {
150 	pa_mainloop_api *api = pa_threaded_mainloop_get_api(pam);
151 	api->defer_enable(pade, true);
152 }
153 
wakeup_lock()154 void PulseAudioSystem::wakeup_lock() {
155 	pa_threaded_mainloop_lock(pam);
156 	pa_mainloop_api *api = pa_threaded_mainloop_get_api(pam);
157 	api->defer_enable(pade, true);
158 	pa_threaded_mainloop_unlock(pam);
159 }
160 
defer_event_callback(pa_mainloop_api * a,pa_defer_event * e,void * userdata)161 void PulseAudioSystem::defer_event_callback(pa_mainloop_api *a, pa_defer_event *e, void *userdata) {
162 	PulseAudioSystem *pas = reinterpret_cast<PulseAudioSystem *>(userdata);
163 	pas->eventCallback(a, e);
164 }
165 
eventCallback(pa_mainloop_api * api,pa_defer_event *)166 void PulseAudioSystem::eventCallback(pa_mainloop_api *api, pa_defer_event *) {
167 	api->defer_enable(pade, false);
168 
169 	if (! bSourceDone || ! bSinkDone || ! bServerDone)
170 		return;
171 
172 	AudioInputPtr ai = g.ai;
173 	AudioOutputPtr ao = g.ao;
174 	AudioInput *raw_ai = ai.get();
175 	AudioOutput *raw_ao = ao.get();
176 	PulseAudioInput *pai = dynamic_cast<PulseAudioInput *>(raw_ai);
177 	PulseAudioOutput *pao = dynamic_cast<PulseAudioOutput *>(raw_ao);
178 
179 	if (raw_ao) {
180 		QString odev = outputDevice();
181 		pa_stream_state ost = pasOutput ? pa_stream_get_state(pasOutput) : PA_STREAM_TERMINATED;
182 		bool do_stop = false;
183 		bool do_start = false;
184 
185 		if (! pao && (ost == PA_STREAM_READY)) {
186 			do_stop = true;
187 		} else if (pao) {
188 			switch (ost) {
189 				case PA_STREAM_TERMINATED: {
190 						if (pasOutput)
191 							pa_stream_unref(pasOutput);
192 
193 						pa_sample_spec pss = qhSpecMap.value(odev);
194 						pa_channel_map pcm = qhChanMap.value(odev);
195 						if ((pss.format != PA_SAMPLE_FLOAT32NE) && (pss.format != PA_SAMPLE_S16NE))
196 							pss.format = PA_SAMPLE_FLOAT32NE;
197 
198 						pss.rate = SAMPLE_RATE;
199 
200 						if ((pss.channels == 0) || (! g.s.doPositionalAudio()))
201 							pss.channels = 1;
202 
203 						pasOutput = pa_stream_new(pacContext, mumble_sink_input, &pss, (pss.channels == 1) ? NULL : &pcm);
204 						pa_stream_set_state_callback(pasOutput, stream_callback, this);
205 						pa_stream_set_write_callback(pasOutput, write_callback, this);
206 
207 						// Fallthrough
208 					}
209 				case PA_STREAM_UNCONNECTED:
210 					do_start = true;
211 					break;
212 				case PA_STREAM_READY: {
213 						if (g.s.iOutputDelay != iDelayCache) {
214 							do_stop = true;
215 						} else if (g.s.doPositionalAudio() != bPositionalCache) {
216 							do_stop = true;
217 						} else if (odev != qsOutputCache) {
218 							do_stop = true;
219 						}
220 						break;
221 					}
222 				default:
223 					break;
224 			}
225 		}
226 		if (do_stop) {
227 			qWarning("PulseAudio: Stopping output");
228 			pa_stream_disconnect(pasOutput);
229 			iSinkId = -1;
230 		} else if (do_start) {
231 			qWarning("PulseAudio: Starting output: %s", qPrintable(odev));
232 			pa_buffer_attr buff;
233 			const pa_sample_spec *pss = pa_stream_get_sample_spec(pasOutput);
234 			const size_t sampleSize = (pss->format == PA_SAMPLE_FLOAT32NE) ? sizeof(float) : sizeof(short);
235 			const unsigned int iBlockLen = pao->iFrameSize * pss->channels * static_cast<unsigned int>(sampleSize);
236 			buff.tlength = iBlockLen * (g.s.iOutputDelay+1);
237 			buff.minreq = iBlockLen;
238 			buff.maxlength = -1;
239 			buff.prebuf = -1;
240 			buff.fragsize = iBlockLen;
241 
242 			iDelayCache = g.s.iOutputDelay;
243 			bPositionalCache = g.s.doPositionalAudio();
244 			qsOutputCache = odev;
245 
246 			pa_stream_connect_playback(pasOutput, qPrintable(odev), &buff, PA_STREAM_ADJUST_LATENCY, NULL, NULL);
247 			pa_context_get_sink_info_by_name(pacContext, qPrintable(odev), sink_info_callback, this);
248 		}
249 	}
250 
251 	if (raw_ai) {
252 		QString idev = inputDevice();
253 		pa_stream_state ist = pasInput ? pa_stream_get_state(pasInput) : PA_STREAM_TERMINATED;
254 		bool do_stop = false;
255 		bool do_start = false;
256 
257 		if (! pai && (ist == PA_STREAM_READY)) {
258 			do_stop = true;
259 		} else if (pai) {
260 			switch (ist) {
261 				case PA_STREAM_TERMINATED: {
262 						if (pasInput)
263 							pa_stream_unref(pasInput);
264 
265 						pa_sample_spec pss = qhSpecMap.value(idev);
266 						if ((pss.format != PA_SAMPLE_FLOAT32NE) && (pss.format != PA_SAMPLE_S16NE))
267 							pss.format = PA_SAMPLE_FLOAT32NE;
268 						pss.rate = SAMPLE_RATE;
269 						pss.channels = 1;
270 
271 						pasInput = pa_stream_new(pacContext, "Microphone", &pss, NULL);
272 						pa_stream_set_state_callback(pasInput, stream_callback, this);
273 						pa_stream_set_read_callback(pasInput, read_callback, this);
274 
275 						// Fallthrough
276 					}
277 
278 				case PA_STREAM_UNCONNECTED:
279 					do_start = true;
280 					break;
281 				case PA_STREAM_READY: {
282 						if (idev != qsInputCache) {
283 							do_stop = true;
284 						}
285 						break;
286 					}
287 				default:
288 					break;
289 			}
290 		}
291 		if (do_stop) {
292 			qWarning("PulseAudio: Stopping input");
293 			pa_stream_disconnect(pasInput);
294 		} else if (do_start) {
295 			qWarning("PulseAudio: Starting input %s",qPrintable(idev));
296 			pa_buffer_attr buff;
297 			const pa_sample_spec *pss = pa_stream_get_sample_spec(pasInput);
298 			const size_t sampleSize = (pss->format == PA_SAMPLE_FLOAT32NE) ? sizeof(float) : sizeof(short);
299 			const unsigned int iBlockLen = pai->iFrameSize * pss->channels * static_cast<unsigned int>(sampleSize);
300 			buff.tlength = iBlockLen;
301 			buff.minreq = iBlockLen;
302 			buff.maxlength = -1;
303 			buff.prebuf = -1;
304 			buff.fragsize = iBlockLen;
305 
306 			qsInputCache = idev;
307 
308 			pa_stream_connect_record(pasInput, qPrintable(idev), &buff, PA_STREAM_ADJUST_LATENCY);
309 		}
310 	}
311 
312 	if (raw_ai) {
313 		QString odev = outputDevice();
314 		QString edev = qhEchoMap.value(odev);
315 		pa_stream_state est = pasSpeaker ? pa_stream_get_state(pasSpeaker) : PA_STREAM_TERMINATED;
316 		bool do_stop = false;
317 		bool do_start = false;
318 
319 		if ((! pai || ! g.s.doEcho()) && (est == PA_STREAM_READY)) {
320 			do_stop = true;
321 		} else if (pai && g.s.doEcho()) {
322 			switch (est) {
323 				case PA_STREAM_TERMINATED: {
324 						if (pasSpeaker)
325 							pa_stream_unref(pasSpeaker);
326 
327 						pa_sample_spec pss = qhSpecMap.value(edev);
328 						pa_channel_map pcm = qhChanMap.value(edev);
329 						if ((pss.format != PA_SAMPLE_FLOAT32NE) && (pss.format != PA_SAMPLE_S16NE))
330 							pss.format = PA_SAMPLE_FLOAT32NE;
331 						pss.rate = SAMPLE_RATE;
332 						if ((pss.channels == 0) || (! g.s.bEchoMulti))
333 							pss.channels = 1;
334 
335 						pasSpeaker = pa_stream_new(pacContext, mumble_echo, &pss, (pss.channels == 1) ? NULL : &pcm);
336 						pa_stream_set_state_callback(pasSpeaker, stream_callback, this);
337 						pa_stream_set_read_callback(pasSpeaker, read_callback, this);
338 
339 						// Fallthrough
340 					}
341 				case PA_STREAM_UNCONNECTED:
342 					do_start = true;
343 					break;
344 				case PA_STREAM_READY: {
345 						if (g.s.bEchoMulti != bEchoMultiCache) {
346 							do_stop = true;
347 						} else if (edev != qsEchoCache) {
348 							do_stop = true;
349 						}
350 						break;
351 					}
352 				default:
353 					break;
354 			}
355 		}
356 		if (do_stop) {
357 			qWarning("PulseAudio: Stopping echo");
358 			pa_stream_disconnect(pasSpeaker);
359 		} else if (do_start) {
360 			qWarning("PulseAudio: Starting echo: %s", qPrintable(edev));
361 			pa_buffer_attr buff;
362 			const pa_sample_spec *pss = pa_stream_get_sample_spec(pasSpeaker);
363 			const size_t sampleSize = (pss->format == PA_SAMPLE_FLOAT32NE) ? sizeof(float) : sizeof(short);
364 			const unsigned int iBlockLen = pai->iFrameSize * pss->channels * static_cast<unsigned int>(sampleSize);
365 			buff.tlength = iBlockLen;
366 			buff.minreq = iBlockLen;
367 			buff.maxlength = -1;
368 			buff.prebuf = -1;
369 			buff.fragsize = iBlockLen;
370 
371 			bEchoMultiCache = g.s.bEchoMulti;
372 			qsEchoCache = edev;
373 
374 			pa_stream_connect_record(pasSpeaker, qPrintable(edev), &buff, PA_STREAM_ADJUST_LATENCY);
375 		}
376 	}
377 }
378 
context_state_callback(pa_context * c,void * userdata)379 void PulseAudioSystem::context_state_callback(pa_context *c, void *userdata) {
380 	PulseAudioSystem *pas = reinterpret_cast<PulseAudioSystem *>(userdata);
381 	pas->contextCallback(c);
382 }
383 
subscribe_callback(pa_context *,pa_subscription_event_type evt,unsigned int,void * userdata)384 void PulseAudioSystem::subscribe_callback(pa_context *, pa_subscription_event_type evt, unsigned int, void *userdata) {
385 	switch (evt & PA_SUBSCRIPTION_EVENT_TYPE_MASK) {
386 		case PA_SUBSCRIPTION_EVENT_NEW:
387 		case PA_SUBSCRIPTION_EVENT_REMOVE:
388 			break;
389 		default:
390 			return;
391 	}
392 	switch (evt & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) {
393 		case PA_SUBSCRIPTION_EVENT_SINK:
394 		case PA_SUBSCRIPTION_EVENT_SOURCE:
395 			break;
396 		default:
397 			return;
398 	}
399 	PulseAudioSystem *pas = reinterpret_cast<PulseAudioSystem *>(userdata);
400 	qWarning("PulseAudio: Sinks or inputs changed (inserted or removed sound card)");
401 	pas->query();
402 }
403 
sink_callback(pa_context *,const pa_sink_info * i,int eol,void * userdata)404 void PulseAudioSystem::sink_callback(pa_context *, const pa_sink_info *i, int eol, void *userdata) {
405 	PulseAudioSystem *pas = reinterpret_cast<PulseAudioSystem *>(userdata);
406 	if (!i || eol) {
407 		pas->bSinkDone = true;
408 		pas->wakeup();
409 		return;
410 	}
411 
412 	const QString name = QString::fromUtf8(i->name);
413 
414 	pas->qhSpecMap.insert(name, i->sample_spec);
415 	pas->qhChanMap.insert(name, i->channel_map);
416 	pas->qhOutput.insert(name, QString::fromUtf8(i->description));
417 	pas->qhEchoMap.insert(name, QString::fromUtf8(i->monitor_source_name));
418 }
419 
source_callback(pa_context *,const pa_source_info * i,int eol,void * userdata)420 void PulseAudioSystem::source_callback(pa_context *, const pa_source_info *i, int eol, void *userdata) {
421 	PulseAudioSystem *pas = reinterpret_cast<PulseAudioSystem *>(userdata);
422 	if (!i || eol) {
423 		pas->bSourceDone = true;
424 		pas->wakeup();
425 		return;
426 	}
427 
428 	const QString name = QString::fromUtf8(i->name);
429 
430 	pas->qhSpecMap.insert(name, i->sample_spec);
431 	pas->qhChanMap.insert(name, i->channel_map);
432 
433 	pas->qhInput.insert(QString::fromUtf8(i->name), QString::fromUtf8(i->description));
434 }
435 
server_callback(pa_context *,const pa_server_info * i,void * userdata)436 void PulseAudioSystem::server_callback(pa_context *, const pa_server_info *i, void *userdata) {
437 	PulseAudioSystem *pas = reinterpret_cast<PulseAudioSystem *>(userdata);
438 
439 	pas->qsDefaultInput = QString::fromUtf8(i->default_source_name);
440 	pas->qsDefaultOutput = QString::fromUtf8(i->default_sink_name);
441 
442 	pas->bServerDone = true;
443 	pas->wakeup();
444 }
445 
sink_info_callback(pa_context *,const pa_sink_info * i,int eol,void * userdata)446 void PulseAudioSystem::sink_info_callback(pa_context *, const pa_sink_info *i, int eol, void *userdata) {
447 	PulseAudioSystem *pas = reinterpret_cast<PulseAudioSystem *>(userdata);
448 	if (!i || eol) {
449 		return;
450 	}
451 
452 	pas->iSinkId = i->index;
453 }
454 
455 
stream_callback(pa_stream * s,void * userdata)456 void PulseAudioSystem::stream_callback(pa_stream *s, void *userdata) {
457 	PulseAudioSystem *pas = reinterpret_cast<PulseAudioSystem *>(userdata);
458 	switch (pa_stream_get_state(s)) {
459 		case PA_STREAM_FAILED:
460 			qWarning("PulseAudio: Stream error: %s", pa_strerror(pa_context_errno(pa_stream_get_context(s))));
461 			break;
462 		default:
463 			break;
464 	}
465 	pas->wakeup();
466 }
467 
read_callback(pa_stream * s,size_t bytes,void * userdata)468 void PulseAudioSystem::read_callback(pa_stream *s, size_t bytes, void *userdata) {
469 	PulseAudioSystem *pas = reinterpret_cast<PulseAudioSystem *>(userdata);
470 
471 	size_t length = bytes;
472 	const void *data = NULL;
473 	pa_stream_peek(s, &data, &length);
474 	if (data == NULL && length > 0) {
475 		qWarning("PulseAudio: pa_stream_peek reports no data at current read index.");
476 	} else if (data == NULL && length == 0) {
477 		qWarning("PulseAudio: pa_stream_peek reports empty memblockq.");
478 	} else if (data == NULL || length == 0) {
479 		qWarning("PulseAudio: invalid pa_stream_peek state encountered.");
480 		return;
481 	}
482 
483 	AudioInputPtr ai = g.ai;
484 	PulseAudioInput *pai = dynamic_cast<PulseAudioInput *>(ai.get());
485 	if (! pai) {
486 		if (length > 0) {
487 			pa_stream_drop(s);
488 		}
489 		pas->wakeup();
490 		return;
491 	}
492 
493 	const pa_sample_spec *pss = pa_stream_get_sample_spec(s);
494 
495 	if (s == pas->pasInput) {
496 		if (!pa_sample_spec_equal(pss, &pai->pssMic)) {
497 			pai->pssMic = *pss;
498 			pai->iMicFreq = pss->rate;
499 			pai->iMicChannels = pss->channels;
500 			if (pss->format == PA_SAMPLE_FLOAT32NE)
501 				pai->eMicFormat = PulseAudioInput::SampleFloat;
502 			else
503 				pai->eMicFormat = PulseAudioInput::SampleShort;
504 			pai->initializeMixer();
505 		}
506 		if (data != NULL) {
507 			pai->addMic(data, static_cast<unsigned int>(length) / pai->iMicSampleSize);
508 		}
509 	} else if (s == pas->pasSpeaker) {
510 		if (!pa_sample_spec_equal(pss, &pai->pssEcho)) {
511 			pai->pssEcho = *pss;
512 			pai->iEchoFreq = pss->rate;
513 			pai->iEchoChannels = pss->channels;
514 			if (pss->format == PA_SAMPLE_FLOAT32NE)
515 				pai->eEchoFormat = PulseAudioInput::SampleFloat;
516 			else
517 				pai->eEchoFormat = PulseAudioInput::SampleShort;
518 			pai->initializeMixer();
519 		}
520 		if (data != NULL) {
521 			pai->addEcho(data, static_cast<unsigned int>(length) / pai->iEchoSampleSize);
522 		}
523 	}
524 
525 	if (length > 0) {
526 		pa_stream_drop(s);
527 	}
528 }
529 
write_callback(pa_stream * s,size_t bytes,void * userdata)530 void PulseAudioSystem::write_callback(pa_stream *s, size_t bytes, void *userdata) {
531 	PulseAudioSystem *pas = reinterpret_cast<PulseAudioSystem *>(userdata);
532 	Q_ASSERT(s == pas->pasOutput);
533 
534 	AudioOutputPtr ao = g.ao;
535 	PulseAudioOutput *pao = dynamic_cast<PulseAudioOutput *>(ao.get());
536 
537 	if (! pao) {
538 		return;
539 	}
540 
541 	const pa_sample_spec *pss = pa_stream_get_sample_spec(s);
542 	const pa_channel_map *pcm = pa_stream_get_channel_map(pas->pasOutput);
543 	if (!pa_sample_spec_equal(pss, &pao->pss) || !pa_channel_map_equal(pcm, &pao->pcm)) {
544 		pao->pss = *pss;
545 		pao->pcm = *pcm;
546 		if (pss->format == PA_SAMPLE_FLOAT32NE)
547 			pao->eSampleFormat = PulseAudioOutput::SampleFloat;
548 		else
549 			pao->eSampleFormat = PulseAudioOutput::SampleShort;
550 		pao->iMixerFreq = pss->rate;
551 		pao->iChannels = pss->channels;
552 		unsigned int chanmasks[pss->channels];
553 		for (int i=0;i<pss->channels;++i) {
554 			unsigned int cm = 0;
555 			switch (pcm->map[i]) {
556 				case PA_CHANNEL_POSITION_LEFT:
557 					cm = SPEAKER_FRONT_LEFT;
558 					break;
559 				case PA_CHANNEL_POSITION_RIGHT:
560 					cm = SPEAKER_FRONT_RIGHT;
561 					break;
562 				case PA_CHANNEL_POSITION_CENTER:
563 					cm = SPEAKER_FRONT_CENTER;
564 					break;
565 				case PA_CHANNEL_POSITION_REAR_LEFT:
566 					cm = SPEAKER_BACK_LEFT;
567 					break;
568 				case PA_CHANNEL_POSITION_REAR_RIGHT:
569 					cm = SPEAKER_BACK_RIGHT;
570 					break;
571 				case PA_CHANNEL_POSITION_REAR_CENTER:
572 					cm = SPEAKER_BACK_CENTER;
573 					break;
574 				case PA_CHANNEL_POSITION_LFE:
575 					cm = SPEAKER_LOW_FREQUENCY;
576 					break;
577 				case PA_CHANNEL_POSITION_SIDE_LEFT:
578 					cm = SPEAKER_SIDE_LEFT;
579 					break;
580 				case PA_CHANNEL_POSITION_SIDE_RIGHT:
581 					cm = SPEAKER_SIDE_RIGHT;
582 					break;
583 				case PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER:
584 					cm = SPEAKER_FRONT_LEFT_OF_CENTER;
585 					break;
586 				case PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER:
587 					cm = SPEAKER_FRONT_RIGHT_OF_CENTER;
588 					break;
589 				default:
590 					cm = 0;
591 					break;
592 			}
593 			chanmasks[i] = cm;
594 		}
595 		pao->initializeMixer(chanmasks);
596 	}
597 
598 	const unsigned int iSampleSize = pao->iSampleSize;
599 	const unsigned int samples = static_cast<unsigned int>(bytes) / iSampleSize;
600 	bool oldAttenuation = pas->bAttenuating;
601 
602 	unsigned char buffer[bytes];
603 	// do we have some mixed output?
604 	if (pao->mix(buffer, samples)) {
605 		// attenuate if instructed to or it's in settings
606 		pas->bAttenuating = (g.bAttenuateOthers || g.s.bAttenuateOthers);
607 
608 	} else {
609 		memset(buffer, 0, bytes);
610 
611 		// attenuate if intructed to (self-activated)
612 		pas->bAttenuating = g.bAttenuateOthers;
613 	}
614 
615 	// if the attenuation state has changed
616 	if (oldAttenuation != pas->bAttenuating) {
617 		pas->setVolumes();
618 	}
619 
620 	pa_stream_write(s, buffer, iSampleSize * samples, NULL, 0, PA_SEEK_RELATIVE);
621 }
622 
volume_sink_input_list_callback(pa_context * c,const pa_sink_input_info * i,int eol,void * userdata)623 void PulseAudioSystem::volume_sink_input_list_callback(pa_context *c, const pa_sink_input_info *i, int eol, void *userdata) {
624 	PulseAudioSystem *pas = reinterpret_cast<PulseAudioSystem *>(userdata);
625 
626 	if (eol == 0) {
627 		// If we're using the default of "enable attenuation on all ouputs" and output from an application is loopbacked,
628 		// both the loopback and the application will be attenuated leading to double attenuation.
629 		if (!g.s.bOnlyAttenuateSameOutput && pas->iSinkId > -1 && !strcmp(i->driver, "module-loopback.c")) {
630 			return;
631 		}
632 		// If we're not attenuating different sinks and the input is not on this sink, don't attenuate. Or,
633 		// if the input is a loopback module and connected to Mumble's sink, also ignore it (loopbacks are used to connect
634 		// sinks). An attenuated loopback means an indirect application attenuation.
635 		if (g.s.bOnlyAttenuateSameOutput && pas->iSinkId > -1) {
636 			if (int(i->sink) != pas->iSinkId || (int(i->sink) == pas->iSinkId && !strcmp(i->driver, "module-loopback.c") && !g.s.bAttenuateLoopbacks)) {
637 				return;
638 			}
639 		}
640 		// ensure we're not attenuating ourselves!
641 		if (strcmp(i->name, mumble_sink_input) != 0) {
642 			// create a new entry
643 			PulseAttenuation patt;
644 			patt.index = i->index;
645 			patt.name = QString::fromUtf8(i->name);
646 			patt.stream_restore_id = QString::fromUtf8(pa_proplist_gets(i->proplist, "module-stream-restore.id"));
647 			patt.normal_volume = i->volume;
648 
649 			// calculate the attenuated volume
650 			pa_volume_t adj = static_cast<pa_volume_t>(PA_VOLUME_NORM * g.s.fOtherVolume);
651 			pa_sw_cvolume_multiply_scalar(&patt.attenuated_volume, &i->volume, adj);
652 
653 			// set it on the sink input
654 			pa_operation_unref(pa_context_set_sink_input_volume(c, i->index, &patt.attenuated_volume, NULL, NULL));
655 
656 			// store it
657 			pas->qhVolumes[i->index] = patt;
658 		}
659 
660 	} else if (eol < 0) {
661 		qWarning("PulseAudio: Sink input introspection error.");
662 	}
663 }
664 
restore_sink_input_list_callback(pa_context * c,const pa_sink_input_info * i,int eol,void * userdata)665 void PulseAudioSystem::restore_sink_input_list_callback(pa_context *c, const pa_sink_input_info *i, int eol, void *userdata) {
666 	PulseAudioSystem *pas = reinterpret_cast<PulseAudioSystem *>(userdata);
667 
668 	if (eol == 0) {
669 		// if we were tracking this specific sink previously
670 		if (pas->qhVolumes.contains(i->index)) {
671 			// and if it has the attenuated volume we applied to it
672 			if (pa_cvolume_equal(&i->volume, &pas->qhVolumes[i->index].attenuated_volume) != 0) {
673 				// mark it as matched
674 				pas->qlMatchedSinks.append(i->index);
675 
676 				// reset the volume to normal
677 				pas->iRemainingOperations++;
678 				pa_operation_unref(pa_context_set_sink_input_volume(c, i->index, &pas->qhVolumes[i->index].normal_volume, restore_volume_success_callback, pas));
679 			}
680 
681 		// otherwise, save for matching at the end of iteration
682 		} else {
683 			QString restore_id = QString::fromUtf8(pa_proplist_gets(i->proplist, "module-stream-restore.id"));
684 			PulseAttenuation patt;
685 			patt.index = i->index;
686 			patt.normal_volume = i->volume;
687 			pas->qhUnmatchedSinks[restore_id] = patt;
688 		}
689 
690 	} else if (eol < 0) {
691 		qWarning("PulseAudio: Sink input introspection error.");
692 
693 	} else {
694 		// build a list of missing streams by iterating our active list
695 		QHash<uint32_t, PulseAttenuation>::const_iterator it;
696 		for (it = pas->qhVolumes.constBegin(); it != pas->qhVolumes.constEnd(); ++it) {
697 			// skip if previously matched
698 			if (pas->qlMatchedSinks.contains(it.key())) {
699 				continue;
700 			}
701 
702 			// check if the restore id matches. the only case where this would
703 			// happen is if the application was reopened during attenuation.
704 			if (pas->qhUnmatchedSinks.contains(it.value().stream_restore_id)) {
705 				PulseAttenuation active_sink = pas->qhUnmatchedSinks[it.value().stream_restore_id];
706 				// if the volume wasn't changed from our attenuation
707 				if (pa_cvolume_equal(&active_sink.normal_volume, &it.value().attenuated_volume) != 0) {
708 					// reset the volume to normal
709 					pas->iRemainingOperations++;
710 					pa_operation_unref(pa_context_set_sink_input_volume(c, active_sink.index, &it.value().normal_volume, restore_volume_success_callback, pas));
711 				}
712 				continue;
713 			}
714 
715 			// at this point, we don't know what happened to the sink. add
716 			// it to a list to check the stream restore database for.
717 			pas->qhMissingSinks[it.value().stream_restore_id] = it.value();
718 		}
719 
720 		// clean up
721 		pas->qlMatchedSinks.clear();
722 		pas->qhUnmatchedSinks.clear();
723 		pas->qhVolumes.clear();
724 
725 		// if we had missing sinks, check the stream restore database
726 		// to see if we can find and update them.
727 		if (pas->qhMissingSinks.count() > 0) {
728 			pas->iRemainingOperations++;
729 			pa_operation_unref(pa_ext_stream_restore_read(c, stream_restore_read_callback, pas));
730 		}
731 
732 		// trigger the volume completion callback;
733 		// necessary so that shutdown actions are called
734 		restore_volume_success_callback(c, 1, pas);
735 	}
736 }
737 
stream_restore_read_callback(pa_context * c,const pa_ext_stream_restore_info * i,int eol,void * userdata)738 void PulseAudioSystem::stream_restore_read_callback(pa_context *c, const pa_ext_stream_restore_info *i, int eol, void *userdata) {
739 	PulseAudioSystem *pas = reinterpret_cast<PulseAudioSystem *>(userdata);
740 
741 	if (eol == 0) {
742 		QString name = QString::fromUtf8(i->name);
743 
744 		// were we looking for this restoration?
745 		if (pas->qhMissingSinks.contains(name)) {
746 			// make sure it still has the volume we gave it
747 			if (pa_cvolume_equal(&pas->qhMissingSinks[name].attenuated_volume, &i->volume) != 0) {
748 				// update the stream restore record
749 				pa_ext_stream_restore_info restore = *i;
750 				restore.volume = pas->qhMissingSinks[name].normal_volume;
751 				pas->iRemainingOperations++;
752 				pa_operation_unref(pa_ext_stream_restore_write(c, PA_UPDATE_REPLACE, &restore, 1, 1, restore_volume_success_callback, pas));
753 			}
754 
755 			pas->qhMissingSinks.remove(name);
756 		}
757 
758 	} else if (eol < 0) {
759 		qWarning("PulseAudio: Couldn't read stream restore database.");
760 		pas->qhMissingSinks.clear();
761 
762 	} else {
763 		// verify missing list is empty
764 		if (pas->qhMissingSinks.count() > 0) {
765 			qWarning("PulseAudio: Failed to match %d stream(s).", pas->qhMissingSinks.count());
766 			pas->qhMissingSinks.clear();
767 		}
768 
769 		// trigger the volume completion callback;
770 		// necessary so that shutdown actions are called
771 		restore_volume_success_callback(c, 1, pas);
772 	}
773 }
774 
restore_volume_success_callback(pa_context *,int,void * userdata)775 void PulseAudioSystem::restore_volume_success_callback(pa_context *, int, void *userdata) {
776 	PulseAudioSystem *pas = reinterpret_cast<PulseAudioSystem *>(userdata);
777 
778 	pas->iRemainingOperations--;
779 
780 	// if there are no more pending volume adjustments and we're shutting down,
781 	// let the main thread know
782 	if (! pas->bRunning && pas->iRemainingOperations == 0) {
783 		pas->qwcWait.wakeAll();
784 	}
785 }
786 
query()787 void PulseAudioSystem::query() {
788 	bSourceDone=bSinkDone=bServerDone = false;
789 	qhInput.clear();
790 	qhOutput.clear();
791 	qhEchoMap.clear();
792 	qhSpecMap.clear();
793 	qhChanMap.clear();
794 	qhInput.insert(QString(), tr("Default Input"));
795 	qhOutput.insert(QString(), tr("Default Output"));
796 	pa_operation_unref(pa_context_get_server_info(pacContext, server_callback, this));
797 	pa_operation_unref(pa_context_get_sink_info_list(pacContext, sink_callback, this));
798 	pa_operation_unref(pa_context_get_source_info_list(pacContext, source_callback, this));
799 	wakeup();
800 }
801 
setVolumes()802 void PulseAudioSystem::setVolumes() {
803 	// set attenuation state and volumes
804 	if (bAttenuating) {
805 		// ensure the volume map is empty, otherwise it may be dangerous to change
806 		if (qhVolumes.empty()) {
807 			// set the new per-application volumes and store the old ones
808 			pa_operation_unref(pa_context_get_sink_input_info_list(pacContext, volume_sink_input_list_callback, this));
809 		}
810 	// clear attenuation state and restore normal volumes
811 	} else {
812 		iRemainingOperations++;
813 		pa_operation_unref(pa_context_get_sink_input_info_list(pacContext, restore_sink_input_list_callback, this));
814 	}
815 }
816 
contextCallback(pa_context * c)817 void PulseAudioSystem::contextCallback(pa_context *c) {
818 	Q_ASSERT(c == pacContext);
819 	switch (pa_context_get_state(c)) {
820 		case PA_CONTEXT_READY:
821 			bPulseIsGood = true;
822 			pa_operation_unref(pa_context_subscribe(pacContext, PA_SUBSCRIPTION_MASK_SOURCE, NULL, this));
823 			pa_operation_unref(pa_context_subscribe(pacContext, PA_SUBSCRIPTION_MASK_SINK, NULL, this));
824 			query();
825 			break;
826 		case PA_CONTEXT_TERMINATED:
827 			qWarning("PulseAudio: Forcibly disconnected from PulseAudio");
828 			break;
829 		case PA_CONTEXT_FAILED:
830 			qWarning("PulseAudio: Connection failure: %s", pa_strerror(pa_context_errno(c)));
831 			break;
832 		default:
833 			return;
834 	}
835 	qmWait.lock();
836 	qwcWait.wakeAll();
837 	qmWait.unlock();
838 }
839 
PulseAudioInputRegistrar()840 PulseAudioInputRegistrar::PulseAudioInputRegistrar() : AudioInputRegistrar(QLatin1String("PulseAudio"), 10) {
841 }
842 
create()843 AudioInput *PulseAudioInputRegistrar::create() {
844 	return new PulseAudioInput();
845 }
846 
getDeviceChoices()847 const QList<audioDevice> PulseAudioInputRegistrar::getDeviceChoices() {
848 	QList<audioDevice> qlReturn;
849 
850 	QStringList qlInputDevs = pasys->qhInput.keys();
851 	qSort(qlInputDevs);
852 
853 	if (qlInputDevs.contains(g.s.qsPulseAudioInput)) {
854 		qlInputDevs.removeAll(g.s.qsPulseAudioInput);
855 		qlInputDevs.prepend(g.s.qsPulseAudioInput);
856 	}
857 
858 	foreach(const QString &dev, qlInputDevs) {
859 		qlReturn << audioDevice(pasys->qhInput.value(dev), dev);
860 	}
861 
862 	return qlReturn;
863 }
864 
setDeviceChoice(const QVariant & choice,Settings & s)865 void PulseAudioInputRegistrar::setDeviceChoice(const QVariant &choice, Settings &s) {
866 	s.qsPulseAudioInput = choice.toString();
867 }
868 
canEcho(const QString & osys) const869 bool PulseAudioInputRegistrar::canEcho(const QString &osys) const {
870 	return (osys == name);
871 }
872 
PulseAudioOutputRegistrar()873 PulseAudioOutputRegistrar::PulseAudioOutputRegistrar() : AudioOutputRegistrar(QLatin1String("PulseAudio"), 10) {
874 }
875 
create()876 AudioOutput *PulseAudioOutputRegistrar::create() {
877 	return new PulseAudioOutput();
878 }
879 
getDeviceChoices()880 const QList<audioDevice> PulseAudioOutputRegistrar::getDeviceChoices() {
881 	QList<audioDevice> qlReturn;
882 
883 	QStringList qlOutputDevs = pasys->qhOutput.keys();
884 	qSort(qlOutputDevs);
885 
886 	if (qlOutputDevs.contains(g.s.qsPulseAudioOutput)) {
887 		qlOutputDevs.removeAll(g.s.qsPulseAudioOutput);
888 		qlOutputDevs.prepend(g.s.qsPulseAudioOutput);
889 	}
890 
891 	foreach(const QString &dev, qlOutputDevs) {
892 		qlReturn << audioDevice(pasys->qhOutput.value(dev), dev);
893 	}
894 
895 	return qlReturn;
896 }
897 
setDeviceChoice(const QVariant & choice,Settings & s)898 void PulseAudioOutputRegistrar::setDeviceChoice(const QVariant &choice, Settings &s) {
899 	s.qsPulseAudioOutput = choice.toString();
900 }
901 
canMuteOthers() const902 bool PulseAudioOutputRegistrar::canMuteOthers() const {
903 	return true;
904 }
905 
PulseAudioInput()906 PulseAudioInput::PulseAudioInput() {
907 	memset(&pssMic, 0, sizeof(pssMic));
908 	memset(&pssEcho, 0, sizeof(pssEcho));
909 	bRunning = true;
910 	if (pasys)
911 		pasys->wakeup_lock();
912 }
913 
~PulseAudioInput()914 PulseAudioInput::~PulseAudioInput() {
915 	bRunning = false;
916 	qmMutex.lock();
917 	qwcWait.wakeAll();
918 	qmMutex.unlock();
919 	wait();
920 	if (pasys)
921 		pasys->wakeup_lock();
922 }
923 
run()924 void PulseAudioInput::run() {
925 	qmMutex.lock();
926 	while (bRunning)
927 		qwcWait.wait(&qmMutex);
928 	qmMutex.unlock();
929 }
930 
PulseAudioOutput()931 PulseAudioOutput::PulseAudioOutput() {
932 	memset(&pss, 0, sizeof(pss));
933 	memset(&pcm, 0, sizeof(pcm));
934 	bRunning = true;
935 	if (pasys)
936 		pasys->wakeup_lock();
937 }
938 
~PulseAudioOutput()939 PulseAudioOutput::~PulseAudioOutput() {
940 	bRunning = false;
941 	qmMutex.lock();
942 	qwcWait.wakeAll();
943 	qmMutex.unlock();
944 	wait();
945 	if (pasys)
946 		pasys->wakeup_lock();
947 }
948 
run()949 void PulseAudioOutput::run() {
950 	qmMutex.lock();
951 	while (bRunning)
952 		qwcWait.wait(&qmMutex);
953 	qmMutex.unlock();
954 }
955