diff --git a/obs/data/locale/en-US.ini b/obs/data/locale/en-US.ini index 33f606f12..997423bc8 100644 --- a/obs/data/locale/en-US.ini +++ b/obs/data/locale/en-US.ini @@ -333,6 +333,10 @@ Basic.Settings.Audio.DesktopDevice2="Desktop Audio Device 2" Basic.Settings.Audio.AuxDevice="Mic/Auxiliary Audio Device" Basic.Settings.Audio.AuxDevice2="Mic/Auxiliary Audio Device 2" Basic.Settings.Audio.AuxDevice3="Mic/Auxiliary Audio Device 3" +Basic.Settings.Audio.EnablePushToMute="Enable Push-to-mute" +Basic.Settings.Audio.PushToMuteDelay="Push-to-mute delay" +Basic.Settings.Audio.EnablePushToTalk="Enable Push-to-talk" +Basic.Settings.Audio.PushToTalkDelay="Push-to-talk delay" # basic mode 'advanced' settings Basic.Settings.Advanced="Advanced" @@ -397,6 +401,7 @@ Hotkeys.MouseButton="Mouse %1" # audio hotkeys Mute="Mute" Unmute="Unmute" +Push-to-mute="Push-to-mute" Push-to-talk="Push-to-talk" # scene item hotkeys diff --git a/obs/forms/OBSBasicSettings.ui b/obs/forms/OBSBasicSettings.ui index efe763354..bcd6998a9 100644 --- a/obs/forms/OBSBasicSettings.ui +++ b/obs/forms/OBSBasicSettings.ui @@ -2014,7 +2014,16 @@ - + + + + true + + + + + + color: rgb(255, 0, 4); diff --git a/obs/window-basic-settings.cpp b/obs/window-basic-settings.cpp index 99b637e78..e9907044e 100644 --- a/obs/window-basic-settings.cpp +++ b/obs/window-basic-settings.cpp @@ -317,6 +317,23 @@ OBSBasicSettings::OBSBasicSettings(QWidget *parent) LoadColorRanges(); LoadFormats(); + auto ReloadAudioSources = [](void *data, calldata_t *param) + { + auto settings = static_cast(data); + auto source = static_cast(calldata_ptr(param, + "source")); + + if (!(obs_source_get_output_flags(source) & OBS_SOURCE_AUDIO)) + return; + + QMetaObject::invokeMethod(settings, "ReloadAudioSources", + Qt::QueuedConnection); + }; + sourceCreated.Connect(obs_get_signal_handler(), "source_create", + ReloadAudioSources, this); + channelChanged.Connect(obs_get_signal_handler(), "channel_change", + ReloadAudioSources, this); + auto ReloadHotkeys = [](void *data, calldata_t*) { auto settings = static_cast(data); @@ -1245,6 +1262,135 @@ void OBSBasicSettings::LoadAudioDevices() } } +void OBSBasicSettings::LoadAudioSources() +{ + auto layout = new QFormLayout(); + layout->setVerticalSpacing(15); + layout->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow); + + ui->audioSourceScrollArea->takeWidget()->deleteLater(); + audioSourceSignals.clear(); + audioSources.clear(); + + auto widget = new QWidget(); + widget->setLayout(layout); + ui->audioSourceScrollArea->setWidget(widget); + + const char *enablePtm = Str("Basic.Settings.Audio.EnablePushToMute"); + const char *ptmDelay = Str("Basic.Settings.Audio.PushToMuteDelay"); + const char *enablePtt = Str("Basic.Settings.Audio.EnablePushToTalk"); + const char *pttDelay = Str("Basic.Settings.Audio.PushToTalkDelay"); + auto AddSource = [&](obs_source_t *source) + { + if (!(obs_source_get_output_flags(source) & OBS_SOURCE_AUDIO)) + return true; + + auto form = new QFormLayout(); + form->setVerticalSpacing(0); + form->setHorizontalSpacing(5); + form->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow); + + auto ptmCB = new SilentUpdateCheckBox(); + ptmCB->setText(enablePtm); + ptmCB->setChecked(obs_source_push_to_mute_enabled(source)); + form->addRow(ptmCB); + + auto ptmSB = new SilentUpdateSpinBox(); + ptmSB->setSuffix(" ms"); + ptmSB->setRange(0, INT_MAX); + ptmSB->setValue(obs_source_get_push_to_mute_delay(source)); + form->addRow(ptmDelay, ptmSB); + + auto pttCB = new SilentUpdateCheckBox(); + pttCB->setText(enablePtt); + pttCB->setChecked(obs_source_push_to_talk_enabled(source)); + form->addRow(pttCB); + + auto pttSB = new SilentUpdateSpinBox(); + pttSB->setSuffix(" ms"); + pttSB->setRange(0, INT_MAX); + pttSB->setValue(obs_source_get_push_to_talk_delay(source)); + form->addRow(pttDelay, pttSB); + + HookWidget(ptmCB, CHECK_CHANGED, AUDIO_CHANGED); + HookWidget(ptmSB, SCROLL_CHANGED, AUDIO_CHANGED); + HookWidget(pttCB, CHECK_CHANGED, AUDIO_CHANGED); + HookWidget(pttSB, SCROLL_CHANGED, AUDIO_CHANGED); + + audioSourceSignals.reserve(audioSourceSignals.size() + 4); + + auto handler = obs_source_get_signal_handler(source); + audioSourceSignals.emplace_back(handler, "push_to_mute_changed", + [](void *data, calldata_t *param) + { + QMetaObject::invokeMethod(static_cast(data), + "setCheckedSilently", + Q_ARG(bool, calldata_bool(param, "enabled"))); + }, ptmCB); + audioSourceSignals.emplace_back(handler, "push_to_mute_delay", + [](void *data, calldata_t *param) + { + QMetaObject::invokeMethod(static_cast(data), + "setValueSilently", + Q_ARG(int, calldata_int(param, "delay"))); + }, ptmSB); + audioSourceSignals.emplace_back(handler, "push_to_talk_changed", + [](void *data, calldata_t *param) + { + QMetaObject::invokeMethod(static_cast(data), + "setCheckedSilently", + Q_ARG(bool, calldata_bool(param, "enabled"))); + }, pttCB); + audioSourceSignals.emplace_back(handler, "push_to_talk_delay", + [](void *data, calldata_t *param) + { + QMetaObject::invokeMethod(static_cast(data), + "setValueSilently", + Q_ARG(int, calldata_int(param, "delay"))); + }, pttSB); + + audioSources.emplace_back(OBSGetWeakRef(source), + ptmCB, pttSB, pttCB, pttSB); + + auto label = new OBSSourceLabel(source); + connect(label, &OBSSourceLabel::Removed, + [=]() + { + LoadAudioSources(); + }); + connect(label, &OBSSourceLabel::Destroyed, + [=]() + { + LoadAudioSources(); + }); + + layout->addRow(label, form); + return true; + }; + + for (int i = 0; i < MAX_CHANNELS; i++) { + obs_source_t *source = obs_get_output_source(i); + if (!source) continue; + + AddSource(source); + obs_source_release(source); + } + + using AddSource_t = decltype(AddSource); + obs_enum_sources([](void *data, obs_source_t *source) + { + auto &AddSource = *static_cast(data); + AddSource(source); + return true; + }, static_cast(&AddSource)); + + + if (layout->rowCount() == 0) + ui->audioSourceScrollArea->hide(); + else + ui->audioSourceScrollArea->show(); +} + void OBSBasicSettings::LoadAudioSettings() { uint32_t sampleRate = config_get_uint(main->Config(), "Audio", @@ -1272,6 +1418,7 @@ void OBSBasicSettings::LoadAudioSettings() ui->channelSetup->setCurrentIndex(1); LoadAudioDevices(); + LoadAudioSources(); loading = false; } @@ -1866,6 +2013,23 @@ void OBSBasicSettings::SaveAudioSettings() SaveComboData(ui->auxAudioDevice2, "Audio", "AuxDevice2"); SaveComboData(ui->auxAudioDevice3, "Audio", "AuxDevice3"); + for (auto &audioSource : audioSources) { + auto source = OBSGetStrongRef(get<0>(audioSource)); + if (!source) + continue; + + auto &ptmCB = get<1>(audioSource); + auto &ptmSB = get<2>(audioSource); + auto &pttCB = get<3>(audioSource); + auto &pttSB = get<4>(audioSource); + + obs_source_enable_push_to_mute(source, ptmCB->isChecked()); + obs_source_set_push_to_mute_delay(source, ptmSB->value()); + + obs_source_enable_push_to_talk(source, pttCB->isChecked()); + obs_source_set_push_to_talk_delay(source, pttSB->value()); + } + main->ResetAudioDevices(); } @@ -2236,6 +2400,11 @@ void OBSBasicSettings::AudioChangedRestart() } } +void OBSBasicSettings::ReloadAudioSources() +{ + LoadAudioSources(); +} + void OBSBasicSettings::VideoChangedRestart() { if (!loading) { diff --git a/obs/window-basic-settings.hpp b/obs/window-basic-settings.hpp index 85fdfb68d..85981b400 100644 --- a/obs/window-basic-settings.hpp +++ b/obs/window-basic-settings.hpp @@ -35,6 +35,30 @@ class OBSHotkeyWidget; #include "ui_OBSBasicSettings.h" +class SilentUpdateCheckBox : public QCheckBox { + Q_OBJECT + +public slots: + void setCheckedSilently(bool checked) + { + bool blocked = blockSignals(true); + setChecked(checked); + blockSignals(blocked); + } +}; + +class SilentUpdateSpinBox : public QSpinBox { + Q_OBJECT + +public slots: + void setValueSilently(int val) + { + bool blocked = blockSignals(true); + setValue(val); + blockSignals(blocked); + } +}; + class OBSFFDeleter { public: @@ -77,6 +101,15 @@ private: OBSPropertiesView *streamEncoderProps = nullptr; OBSPropertiesView *recordEncoderProps = nullptr; + using AudioSource_t = + std::tuple, QPointer, + QPointer, QPointer>; + std::vector audioSources; + std::vector audioSourceSignals; + OBSSignal sourceCreated; + OBSSignal channelChanged; + std::vector>> hotkeys; OBSSignal hotkeyRegistered; OBSSignal hotkeyUnregistered; @@ -161,6 +194,7 @@ private: void LoadListValues(QComboBox *widget, obs_property_t *prop, const char *configName); void LoadAudioDevices(); + void LoadAudioSources(); /* video */ void LoadRendererList(); @@ -205,6 +239,7 @@ private slots: void GeneralChanged(); void AudioChanged(); void AudioChangedRestart(); + void ReloadAudioSources(); void OutputsChanged(); void Stream1Changed(); void VideoChanged();