Skip to content

Commit 763a7f3

Browse files
committed
UI: Add to Settings > Audio ASIO monitoring
This adds a QToolButton to the Audio Settings on Windows. This triggers in turn a dedicated settings for the ASIO monitoring output. If no ASIO driver is detected in the system, the panel displays an explanatory message. The panel allows to: - select a monitoring device; - for each output channel of the ASIO device, one can select any channel from any of the 6 tracks or from the monitoring mix. Signed-off-by: pkv <[email protected]>
1 parent 03082d0 commit 763a7f3

File tree

9 files changed

+129
-20
lines changed

9 files changed

+129
-20
lines changed

frontend/data/locale/en-US.ini

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1309,6 +1309,8 @@ Basic.Settings.Advanced.Video.HdrNominalPeakLevel="HDR Nominal Peak Level"
13091309
Basic.Settings.Advanced.Audio.MonitoringDevice="Monitoring Device"
13101310
Basic.Settings.Advanced.Audio.MonitoringDevice.Default="Default"
13111311
Basic.Settings.Advanced.Audio.DisableAudioDucking="Disable Windows audio ducking"
1312+
Basic.Settings.Advanced.Audio.AsioMonitoringDevice="ASIO Monitoring Device"
1313+
Basic.Settings.Audio.AsioMonitoring="Setup Panel"
13121314
Basic.Settings.Advanced.StreamDelay="Stream Delay"
13131315
Basic.Settings.Advanced.StreamDelay.Duration="Duration"
13141316
Basic.Settings.Advanced.StreamDelay.Preserve="Preserve cutoff point (increase delay) when reconnecting"

frontend/data/themes/Yami.obt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1406,6 +1406,12 @@ QPushButton::menu-indicator {
14061406
width: 25px;
14071407
}
14081408

1409+
QWidget QFormLayout > QToolButton#asioMonitoring {
1410+
min-width: 0px;
1411+
max-width: 16777215px;
1412+
text-align: center;
1413+
}
1414+
14091415
QToolButton {
14101416
border: 1px solid var(--button_border);
14111417
}

frontend/forms/OBSBasicSettings.ui

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6233,6 +6233,29 @@
62336233
</property>
62346234
</widget>
62356235
</item>
6236+
<item row="3" column="0">
6237+
<widget class="QLabel" name="asioDeviceLabel">
6238+
<property name="text">
6239+
<string>Basic.Settings.Advanced.Audio.AsioMonitoringDevice</string>
6240+
</property>
6241+
<property name="buddy">
6242+
<cstring>asioMonitoring</cstring>
6243+
</property>
6244+
</widget>
6245+
</item>
6246+
<item row="3" column="1">
6247+
<widget class="QToolButton" name="asioMonitoring">
6248+
<property name="text">
6249+
<string>Basic.Settings.Audio.AsioMonitoring</string>
6250+
</property>
6251+
<property name="objectName">
6252+
<string>asioMonitoring</string>
6253+
</property>
6254+
<property name="sizePolicy">
6255+
<sizepolicy hsizetype="Minimum" vsizetype="Fixed"/>
6256+
</property>
6257+
</widget>
6258+
</item>
62366259
</layout>
62376260
</widget>
62386261
</item>
@@ -8861,6 +8884,7 @@
88618884
<tabstop>meterDecayRate</tabstop>
88628885
<tabstop>peakMeterType</tabstop>
88638886
<tabstop>monitoringDevice</tabstop>
8887+
<tabstop>asioMonitoring</tabstop>
88648888
<tabstop>disableAudioDucking</tabstop>
88658889
<tabstop>lowLatencyBuffering</tabstop>
88668890
<tabstop>baseResolution</tabstop>

frontend/plugins/asio-output-ui/ASIOSettingsDialog.cpp

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,21 +21,29 @@ ASIOSettingsDialog::ASIOSettingsDialog(QWidget *parent, obs_output_t *output, OB
2121
propertiesView = nullptr;
2222
}
2323

24-
void ASIOSettingsDialog::ShowHideDialog()
24+
void ASIOSettingsDialog::ShowHideDialog(bool enabled)
2525
{
26-
SetupPropertiesView();
26+
SetupPropertiesView(enabled);
2727
setVisible(!isVisible());
2828
}
2929

30-
void ASIOSettingsDialog::SetupPropertiesView()
30+
void ASIOSettingsDialog::SetupPropertiesView(bool enabled)
3131
{
3232
if (propertiesView)
3333
delete propertiesView;
3434

3535
propertiesView = new OBSPropertiesView(_settings, "asio_output",
3636
(PropertiesReloadCallback)obs_get_output_properties, 170);
3737

38-
ui->propertiesLayout->addWidget(propertiesView);
38+
if (enabled) {
39+
ui->propertiesLayout->addWidget(propertiesView);
40+
} else {
41+
QLabel *noAsioLabel = new QLabel(obs_module_text("AsioOutput.Disabled"), this);
42+
noAsioLabel->setWordWrap(true);
43+
noAsioLabel->setAlignment(Qt::AlignCenter);
44+
ui->propertiesLayout->addWidget(noAsioLabel);
45+
adjustSize();
46+
}
3947

4048
connect(propertiesView, &OBSPropertiesView::Changed, this, &ASIOSettingsDialog::PropertiesChanged);
4149
}

frontend/plugins/asio-output-ui/ASIOSettingsDialog.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include <QDialog>
2121
#include <QAction>
2222
#include <QMainWindow>
23+
#include <QLabel>
2324

2425
#include "./forms/ui_output.h"
2526

@@ -31,8 +32,8 @@ class ASIOSettingsDialog : public QDialog {
3132
public:
3233
explicit ASIOSettingsDialog(QWidget *parent = 0, obs_output_t *output = nullptr, OBSData settings = nullptr);
3334
std::unique_ptr<Ui_Output> ui;
34-
void ShowHideDialog();
35-
void SetupPropertiesView();
35+
void ShowHideDialog(bool enabled);
36+
void SetupPropertiesView(bool enabled);
3637
void SaveSettings();
3738
OBSData _settings;
3839
obs_output_t *_output;

frontend/plugins/asio-output-ui/asio-ui-main.cpp

Lines changed: 52 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
#include <obs-frontend-api.h>
1010
#include <QMainWindow>
1111
#include <QAction>
12+
#include <QScreen>
13+
1214
#include <util/util.hpp>
1315
#include <util/platform.h>
1416
#include "ASIOSettingsDialog.h"
@@ -74,21 +76,49 @@ void output_start()
7476
}
7577
}
7678

79+
void callback()
80+
{
81+
QMainWindow *mainWindow = (QMainWindow *)obs_frontend_get_main_window();
82+
QWidget *obsSettingsDialog = nullptr;
83+
const auto topLevels = QApplication::topLevelWidgets();
84+
for (QWidget *widget : topLevels) {
85+
if (widget->isVisible() && QString(widget->metaObject()->className()).contains("OBSBasicSettings")) {
86+
obsSettingsDialog = widget;
87+
break;
88+
}
89+
}
90+
if (!_settingsDialog) {
91+
if (!obsSettingsDialog)
92+
_settingsDialog = new ASIOSettingsDialog(mainWindow, context.output, context.settings);
93+
else
94+
_settingsDialog = new ASIOSettingsDialog(obsSettingsDialog, context.output, context.settings);
95+
_settingsDialog->setAttribute(Qt::WA_DeleteOnClose);
96+
QObject::connect(_settingsDialog, &QObject::destroyed, []() { _settingsDialog = nullptr; });
97+
}
98+
99+
_settingsDialog->ShowHideDialog(context.enabled);
100+
if (obsSettingsDialog) {
101+
QRect settingsRect = obsSettingsDialog->geometry();
102+
QRect asioRect = _settingsDialog->geometry();
103+
QPoint newPos(settingsRect.right() + 100, settingsRect.top());
104+
QScreen *screen = obsSettingsDialog->screen();
105+
QRect desktopRect = screen->availableGeometry();
106+
if (newPos.x() + asioRect.width() > desktopRect.right())
107+
newPos.setX(desktopRect.right() - asioRect.width());
108+
_settingsDialog->move(newPos);
109+
}
110+
}
111+
77112
void addOutputUI(void)
78113
{
79114
QAction *action = (QAction *)obs_frontend_add_tools_menu_qaction(obs_module_text("AsioOutput.Menu"));
80-
81-
QMainWindow *mainWindow = (QMainWindow *)obs_frontend_get_main_window();
115+
action->setObjectName("asioOutputSetupAction");
82116

83117
obs_frontend_push_ui_translation(obs_module_get_string);
84-
_settingsDialog = new ASIOSettingsDialog(mainWindow, context.output, context.settings);
85118
obs_frontend_pop_ui_translation();
86-
87-
auto cb = []() {
88-
_settingsDialog->ShowHideDialog();
89-
};
90-
91-
action->connect(action, &QAction::triggered, cb);
119+
// the UI is added through the callback
120+
action->connect(action, &QAction::triggered, callback);
121+
action->setVisible(false);
92122
}
93123

94124
static void OBSEvent(enum obs_frontend_event event, void *)
@@ -111,10 +141,15 @@ void obs_module_unload(void)
111141
if (output_running)
112142
output_stop();
113143

114-
obs_output_release(context.output);
115-
context.output = nullptr;
116-
obs_data_release(context.settings);
117-
context.settings = nullptr;
144+
if (context.output) {
145+
obs_output_release(context.output);
146+
context.output = nullptr;
147+
}
148+
149+
if (context.settings) {
150+
obs_data_release(context.settings);
151+
context.settings = nullptr;
152+
}
118153
obs_frontend_remove_event_callback(OBSEvent, nullptr);
119154
}
120155

@@ -124,8 +159,11 @@ void obs_module_post_load(void)
124159
return;
125160

126161
context.settings = load_settings();
162+
127163
obs_output_t *const output = obs_output_create("asio_output", "asio_output", context.settings, NULL);
164+
128165
if (output != nullptr) {
166+
context.enabled = true;
129167
context.output = output;
130168
// if there is no json saved, we create a default json which uses the 1st asio device
131169
if (!context.settings) {
@@ -136,5 +174,6 @@ void obs_module_post_load(void)
136174
obs_frontend_add_event_callback(OBSEvent, nullptr);
137175
} else {
138176
blog(LOG_INFO, "Failed to create ASIO output");
177+
addOutputUI();
139178
}
140179
}
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1-
AsioOutput.Menu="ASIO Output"
1+
AsioOutput.Menu="ASIO Output"
2+
AsioOutput.Disabled="No ASIO audio driver was detected in your system. ASIO monitoring is disabled."

frontend/settings/OBSBasicSettings.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -718,6 +718,14 @@ OBSBasicSettings::OBSBasicSettings(QWidget *parent)
718718
if (obs_audio_monitoring_available())
719719
FillAudioMonitoringDevices();
720720

721+
#ifdef _WIN32
722+
connect(ui->asioMonitoring, &QPushButton::clicked, this, &OBSBasicSettings::AsioMonitoringShow);
723+
ui->asioMonitoring->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
724+
ui->formLayout_56->setAlignment(ui->asioMonitoring, Qt::AlignLeft);
725+
#else
726+
ui->asioMonitoring->hide();
727+
ui->asioDeviceLabel->hide();
728+
#endif
721729
connect(ui->channelSetup, &QComboBox::currentIndexChanged, this, &OBSBasicSettings::SurroundWarning);
722730
connect(ui->channelSetup, &QComboBox::currentIndexChanged, this, &OBSBasicSettings::SpeakerLayoutChanged);
723731
connect(ui->lowLatencyBuffering, &QCheckBox::clicked, this, &OBSBasicSettings::LowLatencyBufferingChanged);
@@ -5287,6 +5295,23 @@ void OBSBasicSettings::SimpleRecordingEncoderChanged()
52875295
ui->simpleOutInfoLayout->addWidget(simpleOutRecWarning);
52885296
}
52895297

5298+
#ifdef _WIN32
5299+
void OBSBasicSettings::AsioMonitoringShow()
5300+
{
5301+
QList<QAction *> actions = main->ui->menuTools->actions();
5302+
QAction *asioAction = nullptr;
5303+
for (QAction *action : actions) {
5304+
if (action->objectName() == "asioOutputSetupAction") {
5305+
asioAction = action;
5306+
break;
5307+
}
5308+
}
5309+
if (asioAction) {
5310+
asioAction->trigger();
5311+
}
5312+
}
5313+
#endif
5314+
52905315
void OBSBasicSettings::SurroundWarning(int idx)
52915316
{
52925317
if (idx == lastChannelSetupIdx || idx == -1)

frontend/settings/OBSBasicSettings.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -396,6 +396,9 @@ private slots:
396396
void AudioChanged();
397397
void AudioChangedRestart();
398398
void ReloadAudioSources();
399+
#ifdef _WIN32
400+
void AsioMonitoringShow();
401+
#endif
399402
void SurroundWarning(int idx);
400403
void SpeakerLayoutChanged(int idx);
401404
void LowLatencyBufferingChanged(bool checked);

0 commit comments

Comments
 (0)