1
/* Copyright (C) 2005-2010, Thorvald Natvig <thorvald@natvig.com>
5
Redistribution and use in source and binary forms, with or without
6
modification, are permitted provided that the following conditions
9
- Redistributions of source code must retain the above copyright notice,
10
this list of conditions and the following disclaimer.
11
- Redistributions in binary form must reproduce the above copyright notice,
12
this list of conditions and the following disclaimer in the documentation
13
and/or other materials provided with the distribution.
14
- Neither the name of the Mumble Developers nor the names of its
15
contributors may be used to endorse or promote products derived from this
16
software without specific prior written permission.
18
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
22
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31
#include "PulseAudio.h"
34
#include "MainWindow.h"
36
#include <sys/soundcard.h>
39
#include <sys/ioctl.h>
41
static PulseAudioSystem *pasys = NULL;
45
class PulseAudioInputRegistrar : public AudioInputRegistrar {
47
PulseAudioInputRegistrar();
48
virtual AudioInput *create();
49
virtual const QList<audioDevice> getDeviceChoices();
50
virtual void setDeviceChoice(const QVariant &, Settings &);
51
virtual bool canEcho(const QString &) const;
55
class PulseAudioOutputRegistrar : public AudioOutputRegistrar {
57
PulseAudioOutputRegistrar();
58
virtual AudioOutput *create();
59
virtual const QList<audioDevice> getDeviceChoices();
60
virtual void setDeviceChoice(const QVariant &, Settings &);
63
class PulseAudioInit : public DeferInit {
65
PulseAudioInputRegistrar *airPulseAudio;
66
PulseAudioOutputRegistrar *aorPulseAudio;
68
pasys = new PulseAudioSystem();
70
pasys->qwcWait.wait(&pasys->qmWait, 1000);
71
pasys->qmWait.unlock();
72
if (pasys->bPulseIsGood) {
73
airPulseAudio = new PulseAudioInputRegistrar();
74
aorPulseAudio = new PulseAudioOutputRegistrar();
90
static PulseAudioInit pulseinit;
92
PulseAudioSystem::PulseAudioSystem() {
93
pasInput = pasOutput = pasSpeaker = NULL;
94
bSourceDone=bSinkDone=bServerDone = false;
96
bPositionalCache = false;
99
pam = pa_threaded_mainloop_new();
101
pa_mainloop_api *api = pa_threaded_mainloop_get_api(pam);
103
pa_proplist *proplist;
105
proplist = pa_proplist_new ();
106
pa_proplist_sets (proplist,
107
PA_PROP_APPLICATION_NAME,
109
pa_proplist_sets (proplist,
110
PA_PROP_APPLICATION_ID,
111
"net.sourceforge.mumble.mumble");
112
pa_proplist_sets (proplist,
113
PA_PROP_APPLICATION_ICON_NAME,
115
pa_proplist_sets (proplist,
119
pacContext = pa_context_new_with_proplist (api, NULL, proplist);
120
pa_proplist_free (proplist);
122
pa_context_set_subscribe_callback(pacContext, subscribe_callback, this);
124
pa_context_set_state_callback(pacContext, context_state_callback, this);
125
pa_context_connect(pacContext, NULL, PA_CONTEXT_NOAUTOSPAWN, NULL);
127
pade = api->defer_new(api, defer_event_callback, this);
128
api->defer_enable(pade, false);
130
pa_threaded_mainloop_start(pam);
133
PulseAudioSystem::~PulseAudioSystem() {
134
pa_threaded_mainloop_stop(pam);
135
pa_context_disconnect(pacContext);
136
pa_context_unref(pacContext);
137
pa_threaded_mainloop_free(pam);
140
void PulseAudioSystem::wakeup() {
141
pa_mainloop_api *api = pa_threaded_mainloop_get_api(pam);
142
api->defer_enable(pade, true);
145
void PulseAudioSystem::wakeup_lock() {
146
pa_threaded_mainloop_lock(pam);
147
pa_mainloop_api *api = pa_threaded_mainloop_get_api(pam);
148
api->defer_enable(pade, true);
149
pa_threaded_mainloop_unlock(pam);
152
void PulseAudioSystem::defer_event_callback(pa_mainloop_api *a, pa_defer_event *e, void *userdata) {
153
PulseAudioSystem *pas = reinterpret_cast<PulseAudioSystem *>(userdata);
154
pas->eventCallback(a, e);
157
void PulseAudioSystem::eventCallback(pa_mainloop_api *api, pa_defer_event *) {
158
api->defer_enable(pade, false);
160
if (! bSourceDone || ! bSinkDone || ! bServerDone)
163
AudioInputPtr ai = g.ai;
164
AudioOutputPtr ao = g.ao;
165
AudioInput *raw_ai = ai.get();
166
AudioOutput *raw_ao = ao.get();
167
PulseAudioInput *pai = dynamic_cast<PulseAudioInput *>(raw_ai);
168
PulseAudioOutput *pao = dynamic_cast<PulseAudioOutput *>(raw_ao);
171
QString odev = g.s.qsPulseAudioOutput.isEmpty() ? qsDefaultOutput : g.s.qsPulseAudioOutput;
172
pa_stream_state ost = pasOutput ? pa_stream_get_state(pasOutput) : PA_STREAM_TERMINATED;
173
bool do_stop = false;
174
bool do_start = false;
176
if (! pao && (ost == PA_STREAM_READY)) {
180
case PA_STREAM_TERMINATED: {
182
pa_stream_unref(pasOutput);
183
pa_sample_spec pss = qhSpecMap.value(odev);
185
pss.rate = SAMPLE_RATE;
186
if ((pss.channels == 0) || (! g.s.doPositionalAudio()))
188
if ((pss.format != PA_SAMPLE_FLOAT32NE) && (pss.format != PA_SAMPLE_S16NE))
189
pss.format = PA_SAMPLE_FLOAT32NE;
190
pasOutput = pa_stream_new(pacContext, "Mumble Speakers", &pss, NULL);
191
pa_stream_set_state_callback(pasOutput, stream_callback, this);
192
pa_stream_set_write_callback(pasOutput, write_callback, this);
194
case PA_STREAM_UNCONNECTED:
197
case PA_STREAM_READY: {
198
if (g.s.iOutputDelay != iDelayCache) {
200
} else if (g.s.doPositionalAudio() != bPositionalCache) {
202
} else if (odev != qsOutputCache) {
212
qWarning("PulseAudio: Stopping output");
213
pa_stream_disconnect(pasOutput);
214
} else if (do_start) {
215
qWarning("PulseAudio: Starting output: %s", qPrintable(odev));
217
const pa_sample_spec *pss = pa_stream_get_sample_spec(pasOutput);
218
const unsigned int iBlockLen = ((pao->iFrameSize * pss->rate) / SAMPLE_RATE) * pss->channels * ((pss->format == PA_SAMPLE_FLOAT32NE) ? sizeof(float) : sizeof(short));
219
buff.tlength = iBlockLen * (g.s.iOutputDelay+1);
220
buff.minreq = iBlockLen;
223
buff.fragsize = iBlockLen;
225
iDelayCache = g.s.iOutputDelay;
226
bPositionalCache = g.s.doPositionalAudio();
227
qsOutputCache = odev;
229
pa_stream_connect_playback(pasOutput, qPrintable(odev), &buff, PA_STREAM_ADJUST_LATENCY, NULL, NULL);
234
QString idev = g.s.qsPulseAudioInput.isEmpty() ? qsDefaultInput : g.s.qsPulseAudioInput;
235
pa_stream_state ist = pasInput ? pa_stream_get_state(pasInput) : PA_STREAM_TERMINATED;
236
bool do_stop = false;
237
bool do_start = false;
239
if (! pai && (ist == PA_STREAM_READY)) {
243
case PA_STREAM_TERMINATED: {
245
pa_stream_unref(pasInput);
247
pa_sample_spec pss = qhSpecMap.value(idev);
249
pss.rate = SAMPLE_RATE;
251
if ((pss.format != PA_SAMPLE_FLOAT32NE) && (pss.format != PA_SAMPLE_S16NE))
252
pss.format = PA_SAMPLE_FLOAT32NE;
254
pasInput = pa_stream_new(pacContext, "Microphone", &pss, NULL);
255
pa_stream_set_state_callback(pasInput, stream_callback, this);
256
pa_stream_set_read_callback(pasInput, read_callback, this);
258
case PA_STREAM_UNCONNECTED:
261
case PA_STREAM_READY: {
262
if (idev != qsInputCache) {
272
qWarning("PulseAudio: Stopping input");
273
pa_stream_disconnect(pasInput);
274
} else if (do_start) {
275
qWarning("PulseAudio: Starting input %s",qPrintable(idev));
277
const pa_sample_spec *pss = pa_stream_get_sample_spec(pasInput);
278
const unsigned int iBlockLen = ((pai->iFrameSize * pss->rate) / SAMPLE_RATE) * pss->channels * ((pss->format == PA_SAMPLE_FLOAT32NE) ? sizeof(float) : sizeof(short));
279
buff.tlength = iBlockLen;
280
buff.minreq = iBlockLen;
283
buff.fragsize = iBlockLen;
287
pa_stream_connect_record(pasInput, qPrintable(idev), &buff, PA_STREAM_ADJUST_LATENCY);
292
QString odev = g.s.qsPulseAudioOutput.isEmpty() ? qsDefaultOutput : g.s.qsPulseAudioOutput;
293
QString edev = qhEchoMap.value(odev);
294
pa_stream_state est = pasSpeaker ? pa_stream_get_state(pasSpeaker) : PA_STREAM_TERMINATED;
295
bool do_stop = false;
296
bool do_start = false;
298
if ((! pai || ! g.s.doEcho()) && (est == PA_STREAM_READY)) {
300
} else if (pai && g.s.doEcho()) {
302
case PA_STREAM_TERMINATED: {
304
pa_stream_unref(pasSpeaker);
306
pa_sample_spec pss = qhSpecMap.value(edev);
308
pss.rate = SAMPLE_RATE;
310
if ((pss.format != PA_SAMPLE_FLOAT32NE) && (pss.format != PA_SAMPLE_S16NE))
311
pss.format = PA_SAMPLE_FLOAT32NE;
312
pasSpeaker = pa_stream_new(pacContext, "Mumble Speakers (Echo)", &pss, NULL);
313
pa_stream_set_state_callback(pasSpeaker, stream_callback, this);
314
pa_stream_set_read_callback(pasSpeaker, read_callback, this);
316
case PA_STREAM_UNCONNECTED:
319
case PA_STREAM_READY: {
320
if (edev != qsEchoCache) {
330
qWarning("PulseAudio: Stopping echo");
331
pa_stream_disconnect(pasSpeaker);
332
} else if (do_start) {
333
qWarning("PulseAudio: Starting echo: %s", qPrintable(edev));
335
const pa_sample_spec *pss = pa_stream_get_sample_spec(pasSpeaker);
336
const unsigned int iBlockLen = ((pai->iFrameSize * pss->rate) / SAMPLE_RATE) * pss->channels * ((pss->format == PA_SAMPLE_FLOAT32NE) ? sizeof(float) : sizeof(short));
337
buff.tlength = iBlockLen;
338
buff.minreq = iBlockLen;
341
buff.fragsize = iBlockLen;
345
pa_stream_connect_record(pasSpeaker, qPrintable(edev), &buff, PA_STREAM_ADJUST_LATENCY);
350
void PulseAudioSystem::context_state_callback(pa_context *c, void *userdata) {
351
PulseAudioSystem *pas = reinterpret_cast<PulseAudioSystem *>(userdata);
352
pas->contextCallback(c);
355
void PulseAudioSystem::subscribe_callback(pa_context *, pa_subscription_event_type evt, unsigned int, void *userdata) {
356
switch (evt & PA_SUBSCRIPTION_EVENT_TYPE_MASK) {
357
case PA_SUBSCRIPTION_EVENT_NEW:
358
case PA_SUBSCRIPTION_EVENT_REMOVE:
363
switch (evt & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) {
364
case PA_SUBSCRIPTION_EVENT_SINK:
365
case PA_SUBSCRIPTION_EVENT_SOURCE:
370
PulseAudioSystem *pas = reinterpret_cast<PulseAudioSystem *>(userdata);
371
qWarning("PulseAudio: Sinks or inputs changed (inserted or removed sound card)");
375
void PulseAudioSystem::sink_callback(pa_context *, const pa_sink_info *i, int eol, void *userdata) {
376
PulseAudioSystem *pas = reinterpret_cast<PulseAudioSystem *>(userdata);
378
pas->bSinkDone = true;
383
const QString name = QLatin1String(i->name);
385
pas->qhIndexMap.insert(name, i->index);
386
pas->qhSpecMap.insert(name, i->sample_spec);
387
pas->qhOutput.insert(name, QLatin1String(i->description));
388
pas->qhEchoMap.insert(name, QLatin1String(i->monitor_source_name));
391
void PulseAudioSystem::source_callback(pa_context *, const pa_source_info *i, int eol, void *userdata) {
392
PulseAudioSystem *pas = reinterpret_cast<PulseAudioSystem *>(userdata);
394
pas->bSourceDone = true;
399
const QString name = QLatin1String(i->name);
401
pas->qhIndexMap.insert(name, i->index);
402
pas->qhSpecMap.insert(name, i->sample_spec);
404
if (i->monitor_of_sink == PA_INVALID_INDEX)
405
pas->qhInput.insert(QLatin1String(i->name), QLatin1String(i->description));
408
void PulseAudioSystem::server_callback(pa_context *, const pa_server_info *i, void *userdata) {
409
PulseAudioSystem *pas = reinterpret_cast<PulseAudioSystem *>(userdata);
411
pas->qsDefaultInput = QLatin1String(i->default_source_name);
412
pas->qsDefaultOutput = QLatin1String(i->default_sink_name);
414
pas->bServerDone = true;
418
void PulseAudioSystem::stream_callback(pa_stream *s, void *userdata) {
419
PulseAudioSystem *pas = reinterpret_cast<PulseAudioSystem *>(userdata);
420
switch (pa_stream_get_state(s)) {
421
case PA_STREAM_FAILED:
422
qWarning("PulseAudio: Stream error: %s", pa_strerror(pa_context_errno(pa_stream_get_context(s))));
430
void PulseAudioSystem::read_callback(pa_stream *s, size_t bytes, void *userdata) {
431
PulseAudioSystem *pas = reinterpret_cast<PulseAudioSystem *>(userdata);
433
size_t length = bytes;
435
pa_stream_peek(s, &data, &length);
437
AudioInputPtr ai = g.ai;
438
PulseAudioInput *pai = dynamic_cast<PulseAudioInput *>(ai.get());
445
const pa_sample_spec *pss = pa_stream_get_sample_spec(s);
447
if (s == pas->pasInput) {
448
if (!pa_sample_spec_equal(pss, &pai->pssMic)) {
450
pai->iMicFreq = pss->rate;
451
pai->iMicChannels = pss->channels;
452
if (pss->format == PA_SAMPLE_FLOAT32NE)
453
pai->eMicFormat = AudioInput::SampleFloat;
455
pai->eMicFormat = AudioInput::SampleShort;
456
pai->initializeMixer();
458
pai->addMic(data, length / pai->iMicSampleSize);
459
} else if (s == pas->pasSpeaker) {
460
if (!pa_sample_spec_equal(pss, &pai->pssEcho)) {
462
pai->iEchoFreq = pss->rate;
463
pai->iEchoChannels = pss->channels;
464
if (pss->format == PA_SAMPLE_FLOAT32NE)
465
pai->eEchoFormat = AudioInput::SampleFloat;
467
pai->eEchoFormat = AudioInput::SampleShort;
468
pai->initializeMixer();
470
pai->addEcho(data, length / pai->iEchoSampleSize);
476
void PulseAudioSystem::write_callback(pa_stream *s, size_t bytes, void *userdata) {
477
PulseAudioSystem *pas = reinterpret_cast<PulseAudioSystem *>(userdata);
478
Q_ASSERT(s == pas->pasOutput);
480
AudioOutputPtr ao = g.ao;
481
PulseAudioOutput *pao = dynamic_cast<PulseAudioOutput *>(ao.get());
483
unsigned char buffer[bytes];
486
// Transitioning, but most likely transitions back, so just zero.
487
memset(buffer, 0, bytes);
488
pa_stream_write(s, buffer, bytes, NULL, 0, PA_SEEK_RELATIVE);
493
const pa_sample_spec *pss = pa_stream_get_sample_spec(s);
494
const pa_channel_map *pcm = pa_stream_get_channel_map(pas->pasOutput);
495
if (!pa_sample_spec_equal(pss, &pao->pss) || !pa_channel_map_equal(pcm, &pao->pcm)) {
498
if (pss->format == PA_SAMPLE_FLOAT32NE)
499
pao->eSampleFormat = AudioOutput::SampleFloat;
501
pao->eSampleFormat = AudioOutput::SampleShort;
502
pao->iMixerFreq = pss->rate;
503
pao->iChannels = pss->channels;
504
unsigned int chanmasks[pss->channels];
505
for (int i=0;i<pss->channels;++i) {
507
switch (pcm->map[i]) {
508
case PA_CHANNEL_POSITION_LEFT:
509
cm = SPEAKER_FRONT_LEFT;
511
case PA_CHANNEL_POSITION_RIGHT:
512
cm = SPEAKER_FRONT_RIGHT;
514
case PA_CHANNEL_POSITION_CENTER:
515
cm = SPEAKER_FRONT_CENTER;
517
case PA_CHANNEL_POSITION_REAR_LEFT:
518
cm = SPEAKER_BACK_LEFT;
520
case PA_CHANNEL_POSITION_REAR_RIGHT:
521
cm = SPEAKER_BACK_RIGHT;
523
case PA_CHANNEL_POSITION_REAR_CENTER:
524
cm = SPEAKER_BACK_CENTER;
526
case PA_CHANNEL_POSITION_LFE:
527
cm = SPEAKER_LOW_FREQUENCY;
529
case PA_CHANNEL_POSITION_SIDE_LEFT:
530
cm = SPEAKER_SIDE_LEFT;
532
case PA_CHANNEL_POSITION_SIDE_RIGHT:
533
cm = SPEAKER_SIDE_RIGHT;
535
case PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER:
536
cm = SPEAKER_FRONT_LEFT_OF_CENTER;
538
case PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER:
539
cm = SPEAKER_FRONT_RIGHT_OF_CENTER;
547
pao->initializeMixer(chanmasks);
550
const unsigned int iSampleSize = pao->iSampleSize;
551
const unsigned int samples = bytes / iSampleSize;
553
if (! pao->mix(buffer, samples))
554
memset(buffer, 0, bytes);
555
pa_stream_write(s, buffer, iSampleSize * samples, NULL, 0, PA_SEEK_RELATIVE);
558
void PulseAudioSystem::query() {
559
bSourceDone=bSinkDone=bServerDone = false;
563
qhInput.insert(QString(), tr("Default Input"));
564
qhOutput.insert(QString(), tr("Default Output"));
565
pa_operation_unref(pa_context_get_server_info(pacContext, server_callback, this));
566
pa_operation_unref(pa_context_get_sink_info_list(pacContext, sink_callback, this));
567
pa_operation_unref(pa_context_get_source_info_list(pacContext, source_callback, this));
571
void PulseAudioSystem::contextCallback(pa_context *c) {
572
Q_ASSERT(c == pacContext);
573
switch (pa_context_get_state(c)) {
574
case PA_CONTEXT_READY:
576
pa_operation_unref(pa_context_subscribe(pacContext, PA_SUBSCRIPTION_MASK_SOURCE, NULL, this));
577
pa_operation_unref(pa_context_subscribe(pacContext, PA_SUBSCRIPTION_MASK_SINK, NULL, this));
580
case PA_CONTEXT_TERMINATED:
581
qWarning("PulseAudio: Forcibly disconnected from PulseAudio");
583
case PA_CONTEXT_FAILED:
584
qWarning("PulseAudio: Connection failure: %s", pa_strerror(pa_context_errno(c)));
594
PulseAudioInputRegistrar::PulseAudioInputRegistrar() : AudioInputRegistrar(QLatin1String("PulseAudio"), 10) {
597
AudioInput *PulseAudioInputRegistrar::create() {
598
return new PulseAudioInput();
601
const QList<audioDevice> PulseAudioInputRegistrar::getDeviceChoices() {
602
QList<audioDevice> qlReturn;
604
QStringList qlInputDevs = pasys->qhInput.keys();
607
if (qlInputDevs.contains(g.s.qsPulseAudioInput)) {
608
qlInputDevs.removeAll(g.s.qsPulseAudioInput);
609
qlInputDevs.prepend(g.s.qsPulseAudioInput);
612
foreach(const QString &dev, qlInputDevs) {
613
qlReturn << audioDevice(pasys->qhInput.value(dev), dev);
619
void PulseAudioInputRegistrar::setDeviceChoice(const QVariant &choice, Settings &s) {
620
s.qsPulseAudioInput = choice.toString();
623
bool PulseAudioInputRegistrar::canEcho(const QString &osys) const {
624
return (osys == name);
627
PulseAudioOutputRegistrar::PulseAudioOutputRegistrar() : AudioOutputRegistrar(QLatin1String("PulseAudio"), 10) {
630
AudioOutput *PulseAudioOutputRegistrar::create() {
631
return new PulseAudioOutput();
634
const QList<audioDevice> PulseAudioOutputRegistrar::getDeviceChoices() {
635
QList<audioDevice> qlReturn;
637
QStringList qlOutputDevs = pasys->qhOutput.keys();
640
if (qlOutputDevs.contains(g.s.qsPulseAudioOutput)) {
641
qlOutputDevs.removeAll(g.s.qsPulseAudioOutput);
642
qlOutputDevs.prepend(g.s.qsPulseAudioOutput);
645
foreach(const QString &dev, qlOutputDevs) {
646
qlReturn << audioDevice(pasys->qhOutput.value(dev), dev);
652
void PulseAudioOutputRegistrar::setDeviceChoice(const QVariant &choice, Settings &s) {
653
s.qsPulseAudioOutput = choice.toString();
656
PulseAudioInput::PulseAudioInput() {
657
memset(&pssMic, 0, sizeof(pssMic));
658
memset(&pssEcho, 0, sizeof(pssEcho));
661
pasys->wakeup_lock();
664
PulseAudioInput::~PulseAudioInput() {
671
pasys->wakeup_lock();
674
void PulseAudioInput::run() {
677
qwcWait.wait(&qmMutex);
681
PulseAudioOutput::PulseAudioOutput() {
682
memset(&pss, 0, sizeof(pss));
683
memset(&pcm, 0, sizeof(pcm));
686
pasys->wakeup_lock();
689
PulseAudioOutput::~PulseAudioOutput() {
696
pasys->wakeup_lock();
699
void PulseAudioOutput::run() {
702
qwcWait.wait(&qmMutex);