frontend: Optimize audio mixer updates

This commit is contained in:
Warchamp7
2026-04-10 18:09:07 -04:00
committed by Ryan Foster
parent cf1c425a94
commit b34d17714e
5 changed files with 81 additions and 50 deletions

View File

@@ -165,6 +165,36 @@ VolumeControl::~VolumeControl()
}
}
const QIcon &VolumeControl::getUnassignedIcon()
{
static const QIcon &icon = *new QIcon(":/res/images/unassigned.svg");
return icon;
}
const QIcon &VolumeControl::getMutedIcon()
{
static const QIcon &icon = *new QIcon(":/settings/images/settings/audio.svg");
return icon;
}
const QIcon &VolumeControl::getUnmutedIcon()
{
static const QIcon &icon = *new QIcon(":/settings/images/settings/audio.svg");
return icon;
}
const QIcon &VolumeControl::getMonitorOnIcon()
{
static const QIcon &icon = *new QIcon(":/res/images/headphones.svg");
return icon;
}
const QIcon &VolumeControl::getMonitorOffIcon()
{
static const QIcon &icon = *new QIcon(":/res/images/headphones-off.svg");
return icon;
}
void VolumeControl::obsVolumeChanged(void *data, float)
{
VolumeControl *volControl = static_cast<VolumeControl *>(data);
@@ -600,7 +630,8 @@ void VolumeControl::updateCategoryLabel()
categoryLabel->setText(labelText);
categoryLabel->setAlignment(Qt::AlignCenter);
utils->polishChildren();
style()->polish(categoryLabel);
style()->polish(volumeMeter);
bool forceUpdate = true;
volumeMeter->updateBackgroundCache(forceUpdate);
@@ -727,13 +758,6 @@ void VolumeControl::updateMixerState()
volumeMeter->setMuted((showAsMuted || showAsUnassigned) && !showAsMonitored);
setUseDisabledColors(showAsMuted || !isActive);
// Qt doesn't support overriding the QPushButton icon using pseudo state selectors like :checked
// in QSS so we set a checked class selector on the button to be used instead.
utils->toggleClass(muteButton, "checked", showAsMuted);
utils->toggleClass(monitorButton, "checked", showAsMonitored);
utils->toggleClass(muteButton, "mute-unassigned", showAsUnassigned);
muteButton->setChecked(showAsMuted);
monitorButton->setChecked(showAsMonitored);
@@ -745,36 +769,28 @@ void VolumeControl::updateMixerState()
monitorButton->setToolTip(monitorTooltip);
if (showAsUnassigned) {
QIcon unassignedIcon;
unassignedIcon.addFile(QString::fromUtf8(":/res/images/unassigned.svg"), QSize(16, 16),
QIcon::Mode::Normal, QIcon::State::Off);
muteButton->setIcon(unassignedIcon);
muteButton->setIcon(getUnassignedIcon());
} else if (showAsMuted) {
QIcon mutedIcon;
mutedIcon.addFile(QString::fromUtf8(":/res/images/mute.svg"), QSize(16, 16), QIcon::Mode::Normal,
QIcon::State::Off);
muteButton->setIcon(mutedIcon);
muteButton->setIcon(getMutedIcon());
} else {
QIcon unmutedIcon;
unmutedIcon.addFile(QString::fromUtf8(":/settings/images/settings/audio.svg"), QSize(16, 16),
QIcon::Mode::Normal, QIcon::State::Off);
muteButton->setIcon(unmutedIcon);
muteButton->setIcon(getUnmutedIcon());
}
if (showAsMonitored) {
QIcon monitorOnIcon;
monitorOnIcon.addFile(QString::fromUtf8(":/res/images/headphones.svg"), QSize(16, 16),
QIcon::Mode::Normal, QIcon::State::Off);
monitorButton->setIcon(monitorOnIcon);
monitorButton->setIcon(getMonitorOnIcon());
} else {
QIcon monitorOffIcon;
monitorOffIcon.addFile(QString::fromUtf8(":/res/images/headphones-off.svg"), QSize(16, 16),
QIcon::Mode::Normal, QIcon::State::Off);
monitorButton->setIcon(monitorOffIcon);
monitorButton->setIcon(getMonitorOffIcon());
}
utils->repolish(muteButton);
utils->repolish(monitorButton);
// Qt doesn't support overriding the QPushButton icon using pseudo state selectors like :checked
// in QSS so we set a checked class selector on the button to be used instead.
utils->toggleClass(muteButton, "checked", showAsMuted);
utils->toggleClass(monitorButton, "checked", showAsMonitored);
utils->toggleClass(muteButton, "mute-unassigned", showAsUnassigned);
style()->polish(muteButton);
style()->polish(monitorButton);
updateCategoryLabel();
}

View File

@@ -90,6 +90,12 @@ private:
QMenu *contextMenu;
static const QIcon &getUnassignedIcon();
static const QIcon &getMutedIcon();
static const QIcon &getUnmutedIcon();
static const QIcon &getMonitorOnIcon();
static const QIcon &getMonitorOffIcon();
static void obsVolumeChanged(void *param, float db);
static void obsVolumeMuted(void *data, calldata_t *calldata);
static void obsMixersOrMonitoringChanged(void *data, calldata_t *);
@@ -99,7 +105,6 @@ private:
void setLayoutVertical(bool vertical);
void showVolumeControlMenu(QPoint pos = QPoint(0, 0));
void updateCategoryLabel();
void updateDecayRate();
void updatePeakMeterType();
@@ -156,6 +161,7 @@ public:
}
void updateName();
void updateCategoryLabel();
void refreshColors();
void setLevels(const float magnitude[MAX_AUDIO_CHANNELS], const float peak[MAX_AUDIO_CHANNELS],
const float inputPeak[MAX_AUDIO_CHANNELS]);

View File

@@ -39,7 +39,7 @@
#include "moc_AudioMixer.cpp"
constexpr int GLOBAL_SOURCE_TOTAL = 6;
constexpr int kGlobalSourceTotal = 6;
namespace {
bool isHiddenInMixer(obs_source_t *source)
@@ -371,6 +371,7 @@ void AudioMixer::updateControlVisibility(QString uuid)
bool show = getMixerVisibilityForControl(control);
if (show) {
control->updateMixerState();
control->show();
} else {
control->hide();
@@ -454,7 +455,7 @@ void AudioMixer::updateGlobalSources()
{
globalSources.clear();
for (int i = 1; i <= GLOBAL_SOURCE_TOTAL; i++) {
for (int i = 1; i <= kGlobalSourceTotal; i++) {
OBSSourceAutoRelease source = obs_get_output_source(i);
if (source) {
auto uuidPointer = obs_source_get_uuid(source);
@@ -708,7 +709,7 @@ void AudioMixer::updateVolumeLayouts()
layout->insertWidget(index, volControl);
volControl->setVertical(vertical);
volControl->updateName();
volControl->updateMixerState();
volControl->updateCategoryLabel();
bool showControl = getMixerVisibilityForControl(volControl);
@@ -1015,9 +1016,11 @@ void AudioMixer::obsSourceActivated(void *data, calldata_t *params)
uint32_t flags = obs_source_get_output_flags(source);
if (flags & OBS_SOURCE_AUDIO) {
auto mixer = static_cast<AudioMixer *>(data);
auto uuidPointer = obs_source_get_uuid(source);
QMetaObject::invokeMethod(static_cast<AudioMixer *>(data), "updateControlVisibility",
Qt::QueuedConnection, Q_ARG(QString, QString::fromUtf8(uuidPointer)));
QMetaObject::invokeMethod(mixer, "updateControlVisibility", Qt::QueuedConnection,
Q_ARG(QString, QString::fromUtf8(uuidPointer)));
}
}
@@ -1027,9 +1030,11 @@ void AudioMixer::obsSourceDeactivated(void *data, calldata_t *params)
uint32_t flags = obs_source_get_output_flags(source);
if (flags & OBS_SOURCE_AUDIO) {
auto mixer = static_cast<AudioMixer *>(data);
auto uuidPointer = obs_source_get_uuid(source);
QMetaObject::invokeMethod(static_cast<AudioMixer *>(data), "updateControlVisibility",
Qt::QueuedConnection, Q_ARG(QString, QString::fromUtf8(uuidPointer)));
QMetaObject::invokeMethod(mixer, "updateControlVisibility", Qt::QueuedConnection,
Q_ARG(QString, QString::fromUtf8(uuidPointer)));
}
}
@@ -1040,8 +1045,10 @@ void AudioMixer::obsSourceAudioActivated(void *data, calldata_t *params)
bool audioActive = obs_source_audio_active(source);
if (flags & OBS_SOURCE_AUDIO && audioActive) {
auto mixer = static_cast<AudioMixer *>(data);
auto uuidPointer = obs_source_get_uuid(source);
QMetaObject::invokeMethod(static_cast<AudioMixer *>(data), "addSource", Qt::QueuedConnection,
QMetaObject::invokeMethod(mixer, "addSource", Qt::QueuedConnection,
Q_ARG(QString, QString::fromUtf8(uuidPointer)));
}
}
@@ -1052,8 +1059,10 @@ void AudioMixer::obsSourceAudioDeactivated(void *data, calldata_t *params)
uint32_t flags = obs_source_get_output_flags(source);
if (flags & OBS_SOURCE_AUDIO) {
auto mixer = static_cast<AudioMixer *>(data);
auto uuidPointer = obs_source_get_uuid(source);
QMetaObject::invokeMethod(static_cast<AudioMixer *>(data), "removeSource", Qt::QueuedConnection,
QMetaObject::invokeMethod(mixer, "updateControlVisibility", Qt::QueuedConnection,
Q_ARG(QString, QString::fromUtf8(uuidPointer)));
}
}
@@ -1065,8 +1074,10 @@ void AudioMixer::obsSourceCreate(void *data, calldata_t *params)
bool audioActive = obs_source_audio_active(source);
if (flags & OBS_SOURCE_AUDIO && audioActive) {
auto mixer = static_cast<AudioMixer *>(data);
auto uuidPointer = obs_source_get_uuid(source);
QMetaObject::invokeMethod(static_cast<AudioMixer *>(data), "addSource", Qt::QueuedConnection,
QMetaObject::invokeMethod(mixer, "addSource", Qt::QueuedConnection,
Q_ARG(QString, QString::fromUtf8(uuidPointer)));
}
}
@@ -1077,15 +1088,19 @@ void AudioMixer::obsSourceRemove(void *data, calldata_t *params)
uint32_t flags = obs_source_get_output_flags(source);
if (flags & OBS_SOURCE_AUDIO) {
auto mixer = static_cast<AudioMixer *>(data);
auto uuidPointer = obs_source_get_uuid(source);
QMetaObject::invokeMethod(static_cast<AudioMixer *>(data), "removeSource", Qt::QueuedConnection,
QMetaObject::invokeMethod(mixer, "removeSource", Qt::QueuedConnection,
Q_ARG(QString, QString::fromUtf8(uuidPointer)));
}
}
void AudioMixer::obsSourceRename(void *data, calldata_t *)
{
QMetaObject::invokeMethod(static_cast<AudioMixer *>(data), "queueLayoutUpdate", Qt::QueuedConnection);
auto mixer = static_cast<AudioMixer *>(data);
QMetaObject::invokeMethod(mixer, "queueLayoutUpdate", Qt::QueuedConnection);
}
void AudioMixer::obsSceneItemVisibleChange(void *data, calldata_t *params)

View File

@@ -78,9 +78,7 @@ private:
bool showToolbar{true};
QFrame *mixerFrame{nullptr};
QVBoxLayout *mainLayout{nullptr};
QVBoxLayout *mixerLayout{nullptr};
QStackedWidget *stackedMixerArea{nullptr};
QToolBar *mixerToolbar{nullptr};

View File

@@ -48,11 +48,7 @@ public:
}
void repolish() { repolish(parent); }
static void repolish(QWidget *widget)
{
widget->style()->unpolish(widget);
widget->style()->polish(widget);
}
static void repolish(QWidget *widget) { widget->style()->polish(widget); }
// Adds a style class to the widget
void addClass(const QString &classname) { addClass(parent, classname); }