From 7d0b933a7e9595e0afef854c6f0a2f68a1feea7c Mon Sep 17 00:00:00 2001 From: Colin Stagner <3526918+cbs228@users.noreply.github.com> Date: Sun, 1 Mar 2020 21:47:30 +0100 Subject: [PATCH] PulseAudio: cork input when it is not required MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When self-muted or deafened, "cork" the audio input. Corking instructs the audio source to stop producing audio samples which— when the user is muted—are not needed and would never be transmitted. Without samples to process, the input DSP doesn't run. Corking can halve mumble's CPU consumption when muted, but your mileage may vary. This patch adds the MainWindow::corkAudioInputStream() signal to request changes in the corking state. Other audio backends could be modified to connect to this signal. --- src/mumble/AudioWizard.cpp | 3 +++ src/mumble/MainWindow.cpp | 12 ++++++++++++ src/mumble/MainWindow.h | 14 +++++++++++++- src/mumble/PulseAudio.cpp | 14 ++++++++++++++ src/mumble/PulseAudio.h | 3 +++ src/mumble/main.cpp | 1 + 6 files changed, 46 insertions(+), 1 deletion(-) diff --git a/src/mumble/AudioWizard.cpp b/src/mumble/AudioWizard.cpp index 468bf116a..8e324b243 100644 --- a/src/mumble/AudioWizard.cpp +++ b/src/mumble/AudioWizard.cpp @@ -36,6 +36,7 @@ AudioWizard::AudioWizard(QWidget *p) : QWizard(p) { bInit = true; bLastActive = false; g.bInAudioWizard = true; + g.mw->onChangeMute(); ticker = new QTimer(this); ticker->setObjectName(QLatin1String("Ticker")); @@ -398,6 +399,7 @@ void AudioWizard::reject() { ao->wipe(); aosSource = NULL; g.bInAudioWizard = false; + g.mw->onChangeMute(); QWizard::reject(); } @@ -433,6 +435,7 @@ void AudioWizard::accept() { g.bPosTest = false; restartAudio(); g.bInAudioWizard = false; + g.mw->onChangeMute(); QWizard::accept(); } diff --git a/src/mumble/MainWindow.cpp b/src/mumble/MainWindow.cpp index 4fbfb0fd3..6aefc5c57 100644 --- a/src/mumble/MainWindow.cpp +++ b/src/mumble/MainWindow.cpp @@ -2306,6 +2306,7 @@ void MainWindow::on_qaAudioMute_triggered() { g.sh->setSelfMuteDeafState(g.s.bMute, g.s.bDeaf); } + onChangeMute(); updateTrayIcon(); } @@ -2342,6 +2343,7 @@ void MainWindow::on_qaAudioDeaf_triggered() { g.sh->setSelfMuteDeafState(g.s.bMute, g.s.bDeaf); } + onChangeMute(); updateTrayIcon(); } @@ -2790,6 +2792,15 @@ void MainWindow::whisperReleased(QVariant scdata) { updateTarget(); } +void MainWindow::onChangeMute() +{ + if (!g.ai) { + return; + } + + emit corkAudioInputStream(g.s.bMute && !g.bInAudioWizard); +} + void MainWindow::onResetAudio() { qWarning("MainWindow: Start audio reset"); @@ -2849,6 +2860,7 @@ void MainWindow::serverConnected() { if (g.s.bMute || g.s.bDeaf) { g.sh->setSelfMuteDeafState(g.s.bMute, g.s.bDeaf); + onChangeMute(); } // Update QActions and menues diff --git a/src/mumble/MainWindow.h b/src/mumble/MainWindow.h index e3a50010f..927a51c34 100644 --- a/src/mumble/MainWindow.h +++ b/src/mumble/MainWindow.h @@ -269,6 +269,9 @@ class MainWindow : public QMainWindow, public MessageHandler, public Ui::MainWin void pttReleased(); void whisperReleased(QVariant scdata); void onResetAudio(); + /// Called whenever the self-mute state may have changed. Dispatches + /// corkAudioInputStream() if the desire for audio input has changed. + void onChangeMute(); void showRaiseWindow(); void on_qaFilterToggle_triggered(); /// Opens a save dialog for the image referenced by qtcSaveImageCursor. @@ -279,7 +282,16 @@ class MainWindow : public QMainWindow, public MessageHandler, public Ui::MainWin /// Updates the user's image directory to the given path (any included /// filename is discarded). void updateImagePath(QString filepath) const; - + signals: + /// Reports that audio input is now, or is no longer, required. + /// + /// Signal allows an \ref AudioInput to suspend the input stream + /// when it is not required. + /// + /// @param cork If true, the audio backend MAY now cork/suspend + /// the input stream. If false, the audio backend MUST immediately + /// un-cork/resume the stream. + void corkAudioInputStream(const bool cork); public: MainWindow(QWidget *parent); ~MainWindow() Q_DECL_OVERRIDE; diff --git a/src/mumble/PulseAudio.cpp b/src/mumble/PulseAudio.cpp index 2fa85e3e6..ebe3578be 100644 --- a/src/mumble/PulseAudio.cpp +++ b/src/mumble/PulseAudio.cpp @@ -301,6 +301,11 @@ void PulseAudioSystem::eventCallback(pa_mainloop_api *api, pa_defer_event *) { qsInputCache = idev; pa_stream_connect_record(pasInput, qPrintable(idev), &buff, PA_STREAM_ADJUST_LATENCY); + + // Ensure stream is initially un-muted + pa_stream_cork(pasInput, 0, NULL, NULL); + + connect(g.mw, &MainWindow::corkAudioInputStream, this, &PulseAudioSystem::corkAudioInputStream); } } @@ -371,6 +376,15 @@ void PulseAudioSystem::eventCallback(pa_mainloop_api *api, pa_defer_event *) { } } +void PulseAudioSystem::corkAudioInputStream(const bool cork) +{ + if (pasInput) { + pa_threaded_mainloop_lock(pam); + pa_stream_cork(pasInput, cork, nullptr, nullptr); + pa_threaded_mainloop_unlock(pam); + } +} + void PulseAudioSystem::context_state_callback(pa_context *c, void *userdata) { PulseAudioSystem *pas = reinterpret_cast(userdata); pas->contextCallback(c); diff --git a/src/mumble/PulseAudio.h b/src/mumble/PulseAudio.h index 548a4c4f2..0d000ae48 100644 --- a/src/mumble/PulseAudio.h +++ b/src/mumble/PulseAudio.h @@ -80,6 +80,9 @@ class PulseAudioSystem : public QObject { void setVolumes(); PulseAttenuation* getAttenuation(QString stream_restore_id); + public slots: + void corkAudioInputStream(const bool cork); + public: QHash qhInput; QHash qhOutput; diff --git a/src/mumble/main.cpp b/src/mumble/main.cpp index 60bf416d6..addd902ad 100644 --- a/src/mumble/main.cpp +++ b/src/mumble/main.cpp @@ -479,6 +479,7 @@ int main(int argc, char **argv) { g.p->rescanPlugins(); Audio::start(); + g.mw->onChangeMute(); a.setQuitOnLastWindowClosed(false);