From 67dafef763590dddef7761b7d9935d3f417aaf86 Mon Sep 17 00:00:00 2001 From: Thorvald Natvig Date: Sat, 17 Nov 2007 17:22:40 +0000 Subject: [PATCH] Echo support for PulseAudio (untested) git-svn-id: https://mumble.svn.sourceforge.net/svnroot/mumble/trunk@854 05730e5d-ab1b-0410-a4ac-84af385074fa --- src/mumble/AudioOutput.cpp | 2 +- src/mumble/PulseAudio.cpp | 78 ++++++++++++++++++++++++++++++++------ src/mumble/PulseAudio.h | 2 + 3 files changed, 70 insertions(+), 12 deletions(-) diff --git a/src/mumble/AudioOutput.cpp b/src/mumble/AudioOutput.cpp index 4f0543225..93db34d89 100644 --- a/src/mumble/AudioOutput.cpp +++ b/src/mumble/AudioOutput.cpp @@ -356,13 +356,13 @@ bool AudioSine::decodeNextFrame() { frames--; float t = v; - v += iFrameSize * inc + 0.5 * dinc * iFrameSize * iFrameSize; for (unsigned int i=0;i(sin(t) * 10000.0); inc+=dinc; t+=inc; } + v = t; return true; } else { memset(psBuffer, 0, iFrameSize*2); diff --git a/src/mumble/PulseAudio.cpp b/src/mumble/PulseAudio.cpp index 86e5186bb..29cfba633 100644 --- a/src/mumble/PulseAudio.cpp +++ b/src/mumble/PulseAudio.cpp @@ -73,6 +73,7 @@ PulseAudioSystem::PulseAudioSystem() { psInput = psEcho = NULL; iInputIdx = iEchoIdx = 0; + iEchoSeq = 0; bRunning = true; @@ -85,6 +86,10 @@ PulseAudioSystem::PulseAudioSystem() { pade = api->defer_new(api, defer_event_callback, this); api->defer_enable(pade, false); + + jbJitter = jitter_buffer_init(); + int margin = 320; + jitter_buffer_ctl(jbJitter, JITTER_BUFFER_SET_MARGIN, &margin); start(QThread::TimeCriticalPriority); } @@ -92,6 +97,10 @@ PulseAudioSystem::PulseAudioSystem() { PulseAudioSystem::~PulseAudioSystem() { pa_mainloop_quit(pam, 0); wait(); + jitter_buffer_destroy(jbJitter); + pa_context_disconnect(pacContext); + pa_context_unref(pacContext); + pa_mainloop_free(pam); } void PulseAudioSystem::wakeup() { @@ -276,8 +285,6 @@ void PulseAudioSystem::eventCallback(pa_mainloop_api *api, pa_defer_event *evt) pa_stream_connect_record(pasSpeaker, qPrintable(edev), &buff, PA_STREAM_INTERPOLATE_TIMING); } } - - qWarning("PulseAudio: EventDone"); } void PulseAudioSystem::context_state_callback(pa_context *c, void *userdata) { @@ -368,9 +375,36 @@ void PulseAudioSystem::read_callback(pa_stream *s, size_t bytes, void *userdata) if (pas->iInputIdx == pai->iFrameSize) { pas->iInputIdx = 0; memcpy(pai->psMic, pas->psInput, pai->iFrameSize * sizeof(short)); + + if (g.s.bPulseAudioEcho) { + JitterBufferPacket jbp; + jbp.data = reinterpret_cast(pai->psSpeaker); + spx_int32_t startofs = 0; + jitter_buffer_get(pas->jbJitter, &jbp, pai->iFrameSize, &startofs); + jitter_buffer_update_delay(pas->jbJitter, &jbp, NULL); + jitter_buffer_tick(pas->jbJitter); + } pai->encodeAudioFrame(); } } + } else if (s == pas->pasSpeaker) { + while(samples > 0) { + int ncopy = MIN(pai->iFrameSize - pas->iEchoIdx, samples); + memcpy(pas->psEcho + pas->iEchoIdx, buffer, ncopy * sizeof(short)); + pas->iEchoIdx += ncopy; + samples -= ncopy; + if (pas->iEchoIdx == pai->iFrameSize) { + pas->iEchoIdx = 0; + + JitterBufferPacket jbp; + jbp.data = reinterpret_cast(pas->psEcho); + jbp.len = pai->iFrameSize * sizeof(short); + jbp.span = pai->iFrameSize; + jbp.timestamp = pai->iFrameSize * (++(pas->iEchoSeq)); + + jitter_buffer_put(pas->jbJitter, &jbp); + } + } } pa_stream_drop(s); @@ -441,8 +475,19 @@ AudioInput *PulseAudioInputRegistrar::create() { const QList PulseAudioInputRegistrar::getDeviceChoices() { QList qlReturn; + + QStringList qlInputDevs = pasys.qhInput.keys(); + qSort(qlInputDevs); + + if (qlInputDevs.contains(g.s.qsPulseAudioInput)) { + qlInputDevs.removeAll(g.s.qsPulseAudioInput); + qlInputDevs.prepend(g.s.qsPulseAudioInput); + } + + foreach(const QString &dev, qlInputDevs) { + qlReturn << audioDevice(pasys.qhInput.value(dev), dev); + } - qlReturn << audioDevice(PulseAudioConfig::tr("Default device"), QString()); return qlReturn; } @@ -459,8 +504,19 @@ AudioOutput *PulseAudioOutputRegistrar::create() { const QList PulseAudioOutputRegistrar::getDeviceChoices() { QList qlReturn; - - qlReturn << audioDevice(PulseAudioConfig::tr("Default device"), QString()); + + QStringList qlOutputDevs = pasys.qhOutput.keys(); + qSort(qlOutputDevs); + + if (qlOutputDevs.contains(g.s.qsPulseAudioOutput)) { + qlOutputDevs.removeAll(g.s.qsPulseAudioOutput); + qlOutputDevs.prepend(g.s.qsPulseAudioOutput); + } + + foreach(const QString &dev, qlOutputDevs) { + qlReturn << audioDevice(pasys.qhOutput.value(dev), dev); + } + return qlReturn; } @@ -476,19 +532,19 @@ static ConfigRegistrar registrar(22, PulseAudioConfigDialogNew); PulseAudioConfig::PulseAudioConfig(Settings &st) : ConfigWidget(st) { setupUi(this); -/* - QList qlOutputDevs = cards.qhOutput.keys(); + + QStringList qlOutputDevs = pasys.qhOutput.keys(); qSort(qlOutputDevs); - QList qlInputDevs = cards.qhInput.keys(); + QStringList qlInputDevs = pasys.qhInput.keys(); qSort(qlInputDevs); + foreach(QString dev, qlInputDevs) { -// qcbInputDevice->addItem(cards.qhInput.value(dev), dev); + qcbInputDevice->addItem(pasys.qhInput.value(dev), dev); } foreach(QString dev, qlOutputDevs) { -// qcbOutputDevice->addItem(cards.qhOutput.value(dev), dev); + qcbOutputDevice->addItem(pasys.qhOutput.value(dev), dev); } -*/ } QString PulseAudioConfig::title() const { diff --git a/src/mumble/PulseAudio.h b/src/mumble/PulseAudio.h index 5cbfc2953..d5ede0733 100644 --- a/src/mumble/PulseAudio.h +++ b/src/mumble/PulseAudio.h @@ -77,6 +77,8 @@ class PulseAudioSystem : public QThread { short *psEcho; int iInputIdx; int iEchoIdx; + int iEchoSeq; + JitterBuffer *jbJitter; static void defer_event_callback(pa_mainloop_api *a, pa_defer_event *e, void *userdata); static void context_state_callback(pa_context *c, void *userdata);