Skip to content

Commit fd7d437

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 c65c4ab commit fd7d437

File tree

9 files changed

+130
-21
lines changed

9 files changed

+130
-21
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: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,22 +27,30 @@ ASIOSettingsDialog::ASIOSettingsDialog(QWidget *parent, obs_output_t *output, OB
2727
propertiesView = nullptr;
2828
}
2929

30-
void ASIOSettingsDialog::ShowHideDialog()
30+
void ASIOSettingsDialog::ShowHideDialog(bool enabled)
3131
{
32-
SetupPropertiesView();
32+
SetupPropertiesView(enabled);
3333
setVisible(!isVisible());
3434
}
3535

36-
void ASIOSettingsDialog::SetupPropertiesView()
36+
void ASIOSettingsDialog::SetupPropertiesView(bool enabled)
3737
{
3838
if (propertiesView)
3939
delete propertiesView;
4040

4141
propertiesView = new OBSPropertiesView(_settings, "asio_output",
4242
(PropertiesReloadCallback)obs_get_output_properties, 170);
4343

44-
ui->propertiesLayout->addWidget(propertiesView);
45-
currentDeviceName = g_currentDeviceName;
44+
if (enabled) {
45+
ui->propertiesLayout->addWidget(propertiesView);
46+
currentDeviceName = g_currentDeviceName;
47+
} else {
48+
QLabel *noAsioLabel = new QLabel(obs_module_text("AsioOutput.Disabled"), this);
49+
noAsioLabel->setWordWrap(true);
50+
noAsioLabel->setAlignment(Qt::AlignCenter);
51+
ui->propertiesLayout->addWidget(noAsioLabel);
52+
adjustSize();
53+
}
4654

4755
connect(propertiesView, &OBSPropertiesView::Changed, this, &ASIOSettingsDialog::PropertiesChanged);
4856
}

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"
@@ -75,21 +77,49 @@ void output_start()
7577
}
7678
}
7779

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

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

95125
static void OBSEvent(enum obs_frontend_event event, void *)
@@ -120,10 +150,15 @@ void obs_module_unload(void)
120150
if (output_running)
121151
output_stop();
122152

123-
obs_output_release(context.output);
124-
context.output = nullptr;
125-
obs_data_release(context.settings);
126-
context.settings = nullptr;
153+
if (context.output) {
154+
obs_output_release(context.output);
155+
context.output = nullptr;
156+
}
157+
158+
if (context.settings) {
159+
obs_data_release(context.settings);
160+
context.settings = nullptr;
161+
}
127162
obs_frontend_remove_event_callback(OBSEvent, nullptr);
128163
}
129164

@@ -133,8 +168,11 @@ void obs_module_post_load(void)
133168
return;
134169

135170
context.settings = load_settings();
171+
136172
obs_output_t *const output = obs_output_create("asio_output", "asio_output", context.settings, NULL);
173+
137174
if (output != nullptr) {
175+
context.enabled = true;
138176
context.output = output;
139177

140178
if (!context.settings) {
@@ -145,5 +183,6 @@ void obs_module_post_load(void)
145183
obs_frontend_add_event_callback(OBSEvent, nullptr);
146184
} else {
147185
blog(LOG_INFO, "Failed to create ASIO output");
186+
addOutputUI();
148187
}
149188
}
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)