diff --git a/UI/data/locale/en-US.ini b/UI/data/locale/en-US.ini
index 2eef5a36c..efa4959e8 100644
--- a/UI/data/locale/en-US.ini
+++ b/UI/data/locale/en-US.ini
@@ -93,6 +93,7 @@ Fullscreen="Fullscreen"
Windowed="Windowed"
Percent="Percent"
AspectRatio="Aspect Ratio %1:%2"
+LockVolume="Lock Volume"
# warning if program already open
AlreadyRunning.Title="OBS is already running"
diff --git a/UI/volume-control.cpp b/UI/volume-control.cpp
index 92ec03809..c491a6fff 100644
--- a/UI/volume-control.cpp
+++ b/UI/volume-control.cpp
@@ -276,6 +276,11 @@ VolControl::VolControl(OBSSource source_, bool showConfig, bool vertical)
VolumeChanged();
}
+void VolControl::EnableSlider(bool enable)
+{
+ slider->setEnabled(enable);
+}
+
VolControl::~VolControl()
{
obs_fader_remove_callback(obs_fader, OBSVolumeChanged, this);
diff --git a/UI/volume-control.hpp b/UI/volume-control.hpp
index b357fe11c..82a2bcb50 100644
--- a/UI/volume-control.hpp
+++ b/UI/volume-control.hpp
@@ -252,4 +252,6 @@ public:
void SetMeterDecayRate(qreal q);
void setPeakMeterType(enum obs_peak_meter_type peakMeterType);
+
+ void EnableSlider(bool enable);
};
diff --git a/UI/window-basic-main.cpp b/UI/window-basic-main.cpp
index 0ec29df9c..25f2e3353 100644
--- a/UI/window-basic-main.cpp
+++ b/UI/window-basic-main.cpp
@@ -2842,12 +2842,38 @@ void OBSBasic::MixerRenameSource()
}
}
+static inline bool SourceVolumeLocked(obs_source_t *source)
+{
+ obs_data_t *priv_settings = obs_source_get_private_settings(source);
+ bool lock = obs_data_get_bool(priv_settings, "volume_locked");
+ obs_data_release(priv_settings);
+
+ return lock;
+}
+
+void OBSBasic::LockVolumeControl(bool lock)
+{
+ QAction *action = reinterpret_cast(sender());
+ VolControl *vol = action->property("volControl").value();
+ obs_source_t *source = vol->GetSource();
+
+ obs_data_t *priv_settings = obs_source_get_private_settings(source);
+ obs_data_set_bool(priv_settings, "volume_locked", lock);
+ obs_data_release(priv_settings);
+
+ vol->EnableSlider(!lock);
+}
+
void OBSBasic::VolControlContextMenu()
{
VolControl *vol = reinterpret_cast(sender());
/* ------------------- */
+ QAction lockAction(QTStr("LockVolume"), this);
+ lockAction.setCheckable(true);
+ lockAction.setChecked(SourceVolumeLocked(vol->GetSource()));
+
QAction hideAction(QTStr("Hide"), this);
QAction unhideAllAction(QTStr("UnhideAll"), this);
QAction mixerRenameAction(QTStr("Rename"), this);
@@ -2870,6 +2896,8 @@ void OBSBasic::VolControlContextMenu()
&OBSBasic::HideAudioControl, Qt::DirectConnection);
connect(&unhideAllAction, &QAction::triggered, this,
&OBSBasic::UnhideAllAudioControls, Qt::DirectConnection);
+ connect(&lockAction, &QAction::toggled, this,
+ &OBSBasic::LockVolumeControl, Qt::DirectConnection);
connect(&mixerRenameAction, &QAction::triggered, this,
&OBSBasic::MixerRenameSource, Qt::DirectConnection);
@@ -2895,6 +2923,8 @@ void OBSBasic::VolControlContextMenu()
hideAction.setProperty("volControl",
QVariant::fromValue(vol));
+ lockAction.setProperty("volControl",
+ QVariant::fromValue(vol));
mixerRenameAction.setProperty("volControl",
QVariant::fromValue(vol));
@@ -2916,6 +2946,8 @@ void OBSBasic::VolControlContextMenu()
pasteFiltersAction.setEnabled(true);
QMenu popup;
+ popup.addAction(&lockAction);
+ popup.addSeparator();
popup.addAction(&unhideAllAction);
popup.addAction(&hideAction);
popup.addAction(&mixerRenameAction);
@@ -3019,6 +3051,8 @@ void OBSBasic::ActivateAudioSource(OBSSource source)
"VerticalVolControl");
VolControl *vol = new VolControl(source, true, vertical);
+ vol->EnableSlider(!SourceVolumeLocked(source));
+
double meterDecayRate =
config_get_double(basicConfig, "Audio", "MeterDecayRate");
vol->SetMeterDecayRate(meterDecayRate);
diff --git a/UI/window-basic-main.hpp b/UI/window-basic-main.hpp
index 5eb18e430..9d4e2dd5b 100644
--- a/UI/window-basic-main.hpp
+++ b/UI/window-basic-main.hpp
@@ -660,6 +660,8 @@ private slots:
void TBarChanged(int value);
void TBarReleased();
+ void LockVolumeControl(bool lock);
+
private:
/* OBS Callbacks */
static void SceneReordered(void *data, calldata_t *params);