[Git][pulseaudio/pavucontrol][master] Decay volume meters on monitor stream suspend
Arun Raghavan (@arun)
gitlab at gitlab.freedesktop.org
Mon Jun 23 13:58:46 UTC 2025
Arun Raghavan pushed to branch master at PulseAudio / pavucontrol
Commits:
ce48aec4 by Arun Raghavan at 2025-06-23T09:54:05-04:00
Decay volume meters on monitor stream suspend
If the stream is suspended mid peak, the volume meter just hangs at the
last level. This can happen with a idle suspend timeout of 0 on
PulseAudio, or just by default on PipeWire.
When that happens, we attach to the frame clock and decay to zero in a
second.
Fixes: https://gitlab.freedesktop.org/pulseaudio/pavucontrol/-/issues/174
- - - - -
3 changed files:
- src/mainwindow.cc
- src/minimalstreamwidget.cc
- src/minimalstreamwidget.h
Changes:
=====================================
src/mainwindow.cc
=====================================
@@ -626,7 +626,7 @@ static void suspended_callback(pa_stream *s, void *userdata) {
MainWindow *w = static_cast<MainWindow*>(userdata);
if (pa_stream_is_suspended(s))
- w->updateVolumeMeter(pa_stream_get_device_index(s), PA_INVALID_INDEX, -1);
+ w->updateVolumeMeter(pa_stream_get_device_index(s), pa_stream_get_monitor_stream(s), -1);
}
static void read_callback(pa_stream *s, size_t length, void *userdata) {
@@ -1091,13 +1091,15 @@ void MainWindow::updateDeviceInfo(const pa_ext_device_restore_info &info) {
void MainWindow::updateVolumeMeter(uint32_t source_index, uint32_t sink_input_idx, double v) {
+ MinimalStreamWidget *sw = NULL;
if (sink_input_idx != PA_INVALID_INDEX) {
SinkInputWidget *w;
if (sinkInputWidgets.count(sink_input_idx)) {
w = sinkInputWidgets[sink_input_idx];
- w->updatePeak(v);
+ sw = static_cast<MinimalStreamWidget*>(w);
+ goto done;
}
} else {
@@ -1105,22 +1107,38 @@ void MainWindow::updateVolumeMeter(uint32_t source_index, uint32_t sink_input_id
for (std::map<uint32_t, SinkWidget*>::iterator i = sinkWidgets.begin(); i != sinkWidgets.end(); ++i) {
SinkWidget* w = i->second;
- if (w->monitor_index == source_index)
- w->updatePeak(v);
+ if (w->monitor_index == source_index) {
+ sw = static_cast<MinimalStreamWidget*>(w);
+ goto done;
+ }
}
for (std::map<uint32_t, SourceWidget*>::iterator i = sourceWidgets.begin(); i != sourceWidgets.end(); ++i) {
SourceWidget* w = i->second;
- if (w->index == source_index)
- w->updatePeak(v);
+ if (w->index == source_index) {
+ sw = static_cast<MinimalStreamWidget*>(w);
+ goto done;
+ }
}
for (std::map<uint32_t, SourceOutputWidget*>::iterator i = sourceOutputWidgets.begin(); i != sourceOutputWidgets.end(); ++i) {
SourceOutputWidget* w = i->second;
- if (w->sourceIndex() == source_index)
- w->updatePeak(v);
+ if (w->sourceIndex() == source_index) {
+ sw = static_cast<MinimalStreamWidget*>(w);
+ goto done;
+ }
+ }
+ }
+
+done:
+ if (sw) {
+ if (v == -1) {
+ sw->decayToZero();
+ } else {
+ sw->stopDecay();
+ sw->updatePeak(v);
}
}
}
=====================================
src/minimalstreamwidget.cc
=====================================
@@ -36,7 +36,9 @@ MinimalStreamWidget::MinimalStreamWidget(BaseObjectType* cobject) :
peak(NULL),
updating(false),
volumeMeterEnabled(false),
- volumeMeterVisible(true) {
+ volumeMeterVisible(true),
+ decayTickId(0),
+ decayLastFrameTime(-1) {
}
MinimalStreamWidget::~MinimalStreamWidget() {
@@ -61,22 +63,27 @@ void MinimalStreamWidget::init() {
peakProgressBar.hide();
}
-#define DECAY_STEP (1.0 / PEAKS_RATE)
+void MinimalStreamWidget::stopDecay() {
+ if (decayTickId) {
+ remove_tick_callback(decayTickId);
+ decayTickId = 0;
+ }
+}
-void MinimalStreamWidget::updatePeak(double v) {
- if (lastPeak >= DECAY_STEP)
- if (v < lastPeak - DECAY_STEP)
- v = lastPeak - DECAY_STEP;
+void MinimalStreamWidget::updatePeak(double v, double decayStep) {
+ if (lastPeak >= decayStep)
+ if (v < lastPeak - decayStep)
+ v = lastPeak - decayStep;
lastPeak = v;
- if (v >= 0) {
- peakProgressBar.set_sensitive(TRUE);
- peakProgressBar.set_fraction(v);
- } else {
- peakProgressBar.set_sensitive(FALSE);
- peakProgressBar.set_fraction(0);
- }
+ if (v >= 0) {
+ peakProgressBar.set_sensitive(TRUE);
+ peakProgressBar.set_fraction(v);
+ } else {
+ peakProgressBar.set_sensitive(FALSE);
+ peakProgressBar.set_fraction(0);
+ }
enableVolumeMeter();
}
@@ -98,6 +105,40 @@ void MinimalStreamWidget::setVolumeMeterVisible(bool v) {
peakProgressBar.show();
}
} else {
+ stopDecay();
peakProgressBar.hide();
}
}
+
+bool MinimalStreamWidget::decayOnTick(const Glib::RefPtr<Gdk::FrameClock>& frameClock) {
+ auto frameTime = frameClock->get_frame_time();
+
+ if (lastPeak == 0) {
+ decayTickId = 0;
+ return false;
+ }
+
+ // Scale elapsed time (µs) so we decay in at most 1 second
+ if (frameTime != decayLastFrameTime)
+ updatePeak(0, (frameTime - decayLastFrameTime) / 1000000.0);
+
+ decayLastFrameTime = frameTime;
+
+ return true;
+}
+
+void MinimalStreamWidget::decayToZero() {
+ if (decayTickId)
+ stopDecay();
+
+ auto frameClock = get_frame_clock();
+
+ if (!frameClock) {
+ /* Widget isn't visible, set all the way to 0 */
+ updatePeak(0, 1.0);
+ return;
+ }
+
+ decayLastFrameTime = frameClock->get_frame_time();
+ decayTickId = add_tick_callback(sigc::mem_fun(*this, &MinimalStreamWidget::decayOnTick));
+}
=====================================
src/minimalstreamwidget.h
=====================================
@@ -25,6 +25,7 @@
#include <pulse/pulseaudio.h>
#define PEAKS_RATE 144
+#define DECAY_STEP (1.0 / PEAKS_RATE)
class MinimalStreamWidget : public Gtk::Box {
public:
@@ -50,17 +51,22 @@ public:
bool volumeMeterEnabled;
void enableVolumeMeter();
- void updatePeak(double v);
+ void updatePeak(double v, double decayStep = DECAY_STEP);
void setVolumeMeterVisible(bool v);
+ void decayToZero();
+ void stopDecay();
+
protected:
/* Subclasses must call this after the constructor to finalize the initial
* layout. */
void init();
+ bool decayOnTick(const Glib::RefPtr<Gdk::FrameClock>& frame_clock);
private :
bool volumeMeterVisible;
-
+ guint decayTickId;
+ gint64 decayLastFrameTime;
};
#endif
View it on GitLab: https://gitlab.freedesktop.org/pulseaudio/pavucontrol/-/commit/ce48aec45ffc551c6456f74a5134f23153f322f5
--
View it on GitLab: https://gitlab.freedesktop.org/pulseaudio/pavucontrol/-/commit/ce48aec45ffc551c6456f74a5134f23153f322f5
You're receiving this email because of your account on gitlab.freedesktop.org.
More information about the pulseaudio-commits
mailing list