UI: Prevent thread stalls with fader/volume widgets
When the OBS signal is triggered for these widgets, the invokeMethod could cause the thread to stall, which could make it wait much longer than necessary to output audio data. When that happens, it causes audio monitoring to get backed up and get unnecessarily delayed, as well as cause general audio buffering in libobs to increase unnecessarily. A simple fix both in terms of preventing that stall and improving UI performance is to not call invokeMethod to update the widget each time, and then instead have those widgets update themselves via a timer at a specific interval.
This commit is contained in:
@@ -17,6 +17,8 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
QWeakPointer<VolumeMeterTimer> VolumeMeter::updateTimer;
|
||||
|
||||
void VolControl::OBSVolumeChanged(void *data, float db)
|
||||
{
|
||||
Q_UNUSED(db);
|
||||
@@ -30,11 +32,10 @@ void VolControl::OBSVolumeLevel(void *data, float level, float mag,
|
||||
{
|
||||
VolControl *volControl = static_cast<VolControl*>(data);
|
||||
|
||||
QMetaObject::invokeMethod(volControl, "VolumeLevel",
|
||||
Q_ARG(float, mag),
|
||||
Q_ARG(float, level),
|
||||
Q_ARG(float, peak),
|
||||
Q_ARG(bool, muted));
|
||||
if (muted)
|
||||
level = mag = peak = 0.0f;
|
||||
|
||||
volControl->volMeter->setLevels(mag, level, peak);
|
||||
}
|
||||
|
||||
void VolControl::OBSVolumeMuted(void *data, calldata_t *calldata)
|
||||
@@ -256,30 +257,51 @@ VolumeMeter::VolumeMeter(QWidget *parent)
|
||||
peakColor.setRgb(0x3E, 0xF1, 0x2B);
|
||||
peakHoldColor.setRgb(0x00, 0x00, 0x00);
|
||||
|
||||
resetTimer = new QTimer(this);
|
||||
connect(resetTimer, SIGNAL(timeout()), this, SLOT(resetState()));
|
||||
updateTimerRef = updateTimer.toStrongRef();
|
||||
if (!updateTimerRef) {
|
||||
updateTimerRef = QSharedPointer<VolumeMeterTimer>::create();
|
||||
updateTimerRef->start(100);
|
||||
updateTimer = updateTimerRef;
|
||||
}
|
||||
|
||||
resetState();
|
||||
updateTimerRef->AddVolControl(this);
|
||||
}
|
||||
|
||||
void VolumeMeter::resetState(void)
|
||||
VolumeMeter::~VolumeMeter()
|
||||
{
|
||||
setLevels(0.0f, 0.0f, 0.0f);
|
||||
if (resetTimer->isActive())
|
||||
resetTimer->stop();
|
||||
updateTimerRef->RemoveVolControl(this);
|
||||
}
|
||||
|
||||
void VolumeMeter::setLevels(float nmag, float npeak, float npeakHold)
|
||||
{
|
||||
mag = nmag;
|
||||
peak = npeak;
|
||||
peakHold = npeakHold;
|
||||
uint64_t ts = os_gettime_ns();
|
||||
QMutexLocker locker(&dataMutex);
|
||||
|
||||
update();
|
||||
mag += nmag;
|
||||
peak += npeak;
|
||||
peakHold += npeakHold;
|
||||
multiple += 1.0f;
|
||||
lastUpdateTime = ts;
|
||||
}
|
||||
|
||||
if (resetTimer->isActive())
|
||||
resetTimer->stop();
|
||||
resetTimer->start(1000);
|
||||
inline void VolumeMeter::calcLevels()
|
||||
{
|
||||
uint64_t ts = os_gettime_ns();
|
||||
QMutexLocker locker(&dataMutex);
|
||||
|
||||
if (lastUpdateTime && ts - lastUpdateTime > 1000000000) {
|
||||
mag = peak = peakHold = 0.0f;
|
||||
multiple = 1.0f;
|
||||
lastUpdateTime = 0;
|
||||
}
|
||||
|
||||
if (multiple > 0.0f) {
|
||||
curMag = mag / multiple;
|
||||
curPeak = peak / multiple;
|
||||
curPeakHold = peakHold / multiple;
|
||||
|
||||
mag = peak = peakHold = multiple = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
void VolumeMeter::paintEvent(QPaintEvent *event)
|
||||
@@ -292,9 +314,11 @@ void VolumeMeter::paintEvent(QPaintEvent *event)
|
||||
int width = size().width();
|
||||
int height = size().height();
|
||||
|
||||
int scaledMag = int((float)width * mag);
|
||||
int scaledPeak = int((float)width * peak);
|
||||
int scaledPeakHold = int((float)width * peakHold);
|
||||
calcLevels();
|
||||
|
||||
int scaledMag = int((float)width * curMag);
|
||||
int scaledPeak = int((float)width * curPeak);
|
||||
int scaledPeakHold = int((float)width * curPeakHold);
|
||||
|
||||
gradient.setStart(qreal(scaledMag), 0);
|
||||
gradient.setFinalStop(qreal(scaledPeak), 0);
|
||||
@@ -325,3 +349,19 @@ void VolumeMeter::paintEvent(QPaintEvent *event)
|
||||
scaledPeakHold, height);
|
||||
|
||||
}
|
||||
|
||||
void VolumeMeterTimer::AddVolControl(VolumeMeter *meter)
|
||||
{
|
||||
volumeMeters.push_back(meter);
|
||||
}
|
||||
|
||||
void VolumeMeterTimer::RemoveVolControl(VolumeMeter *meter)
|
||||
{
|
||||
volumeMeters.removeOne(meter);
|
||||
}
|
||||
|
||||
void VolumeMeterTimer::timerEvent(QTimerEvent*)
|
||||
{
|
||||
for (VolumeMeter *meter : volumeMeters)
|
||||
meter->update();
|
||||
}
|
||||
|
Reference in New Issue
Block a user