Ver Fonte

Revert service json lookup refactor in UI

Certain services have custom server lits handling which I had forgotten
about, so although it would have been nice to have this refactor, we'll
have to live with relying on the plugin properties object directly for a
while.

This also reverts obsproject/obs-studio#6530 and
obsproject/obs-studio#6683 because that change depended on this
problematic refactor code.

This reverts commits:
f2e6122881e6b8be3470d5574235afa32a4badc5,
bc80d0ca95a3c79cf1f4bc24df437f4ace125e30,
050a29da1a7ad620f05fbd2927786da2f36d85b9,
22ffc04f735830de19a654cd94839504313afb0a,
275e510aad8161bdcd101828f45584a0430ac65e,
2fa5ffe4dfdb50acaa7df4b7f4f80cf1d12cf913.
jp9000 há 3 anos atrás
pai
commit
0b9a8aa1fd

+ 0 - 2
UI/CMakeLists.txt

@@ -152,8 +152,6 @@ target_sources(
           crash-report.cpp
           crash-report.hpp
           display-helpers.hpp
-          streaming-helpers.cpp
-          streaming-helpers.hpp
           platform.hpp
           qt-display.cpp
           qt-display.hpp

+ 0 - 1
UI/data/locale/en-US.ini

@@ -1084,7 +1084,6 @@ Basic.Settings.Advanced.StreamDelay.Duration="Duration"
 Basic.Settings.Advanced.StreamDelay.Preserve="Preserve cutoff point (increase delay) when reconnecting"
 Basic.Settings.Advanced.StreamDelay.MemoryUsage="Estimated Memory Usage: %1 MB"
 Basic.Settings.Advanced.Network="Network"
-Basic.Settings.Advanced.Network.Disabled="The currently selected streaming protocol does not support changing network settings."
 Basic.Settings.Advanced.Network.BindToIP="Bind to IP"
 Basic.Settings.Advanced.Network.EnableNewSocketLoop="Enable network optimizations"
 Basic.Settings.Advanced.Network.EnableLowLatencyMode="Enable TCP pacing"

+ 2 - 9
UI/forms/AutoConfigStreamPage.ui

@@ -6,7 +6,7 @@
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>726</width>
+    <width>692</width>
     <height>407</height>
    </rect>
   </property>
@@ -89,14 +89,7 @@
           <number>0</number>
          </property>
          <item>
-          <widget class="QComboBox" name="service">
-           <property name="sizePolicy">
-            <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
-             <horstretch>0</horstretch>
-             <verstretch>0</verstretch>
-            </sizepolicy>
-           </property>
-          </widget>
+          <widget class="QComboBox" name="service"/>
          </item>
          <item>
           <widget class="UrlPushButton" name="moreInfoButton">

+ 7 - 14
UI/forms/OBSBasicSettings.ui

@@ -5565,15 +5565,8 @@
                    <property name="topMargin">
                     <number>2</number>
                    </property>
-                   <item row="0" column="1">
-                    <widget class="QLabel" name="advNetworkDisabled">
-                     <property name="text">
-                      <string>Basic.Settings.Advanced.Network.Disabled</string>
-                     </property>
-                    </widget>
-                   </item>
-                   <item row="1" column="0">
-                    <widget class="QLabel" name="bindToIPLabel">
+                   <item row="0" column="0">
+                    <widget class="QLabel" name="label_27">
                      <property name="text">
                       <string>Basic.Settings.Advanced.Network.BindToIP</string>
                      </property>
@@ -5582,17 +5575,17 @@
                      </property>
                     </widget>
                    </item>
-                   <item row="1" column="1">
+                   <item row="0" column="1">
                     <widget class="QComboBox" name="bindToIP"/>
                    </item>
-                   <item row="3" column="1">
+                   <item row="2" column="1">
                     <widget class="QCheckBox" name="enableNewSocketLoop">
                      <property name="text">
                       <string>Basic.Settings.Advanced.Network.EnableNewSocketLoop</string>
                      </property>
                     </widget>
                    </item>
-                   <item row="4" column="1">
+                   <item row="3" column="1">
                     <widget class="QCheckBox" name="enableLowLatencyMode">
                      <property name="enabled">
                       <bool>false</bool>
@@ -5602,7 +5595,7 @@
                      </property>
                     </widget>
                    </item>
-                   <item row="3" column="0">
+                   <item row="2" column="0">
                     <spacer name="horizontalSpacer_7">
                      <property name="orientation">
                       <enum>Qt::Horizontal</enum>
@@ -5615,7 +5608,7 @@
                      </property>
                     </spacer>
                    </item>
-                   <item row="2" column="1">
+                   <item row="1" column="1">
                     <widget class="QCheckBox" name="dynBitrate">
                      <property name="toolTip">
                       <string>Basic.Settings.Output.DynamicBitrate.TT</string>

+ 0 - 205
UI/streaming-helpers.cpp

@@ -1,205 +0,0 @@
-#include "streaming-helpers.hpp"
-#include "qt-wrappers.hpp"
-#include "obs-app.hpp"
-
-#include "../plugins/rtmp-services/rtmp-format-ver.h"
-
-#include <util/platform.h>
-#include <util/util.hpp>
-#include <obs.h>
-
-using namespace json11;
-
-static Json open_json_file(const char *path)
-{
-	BPtr<char> file_data = os_quick_read_utf8_file(path);
-	if (!file_data)
-		return Json();
-
-	std::string err;
-	Json json = Json::parse(file_data, err);
-	if (json["format_version"].int_value() != RTMP_SERVICES_FORMAT_VERSION)
-		return Json();
-	return json;
-}
-
-static inline bool name_matches(const Json &service, const char *name)
-{
-	if (service["name"].string_value() == name)
-		return true;
-
-	auto &alt_names = service["alt_names"].array_items();
-	for (const Json &alt_name : alt_names) {
-		if (alt_name.string_value() == name) {
-			return true;
-		}
-	}
-
-	return false;
-}
-
-Json get_services_json()
-{
-	obs_module_t *mod = obs_get_module("rtmp-services");
-	Json root;
-
-	BPtr<char> file = obs_module_get_config_path(mod, "services.json");
-	if (file)
-		root = open_json_file(file);
-
-	if (root.is_null()) {
-		file = obs_find_module_file(mod, "services.json");
-		if (file)
-			root = open_json_file(file);
-	}
-
-	return root;
-}
-
-Json get_service_from_json(const Json &root, const char *name)
-{
-	auto &services = root["services"].array_items();
-	for (const Json &service : services) {
-		if (name_matches(service, name)) {
-			return service;
-		}
-	}
-
-	return Json();
-}
-
-bool StreamSettingsUI::IsServiceOutputHasNetworkFeatures()
-{
-	if (IsCustomService())
-		return ui_customServer->text().startsWith("rtmp");
-
-	Json service = get_service_from_json(
-		GetServicesJson(), QT_TO_UTF8(ui_service->currentText()));
-
-	if (!service["recommended"]["output"].is_string())
-		return true;
-
-	if (service["recommended"]["output"].string_value().compare(
-		    "rtmp_output") == 0)
-		return true;
-
-	return false;
-}
-
-void StreamSettingsUI::UpdateMoreInfoLink()
-{
-	if (IsCustomService()) {
-		ui_moreInfoButton->hide();
-		return;
-	}
-
-	QString serviceName = ui_service->currentText();
-	Json service = get_service_from_json(GetServicesJson(),
-					     QT_TO_UTF8(serviceName));
-
-	const std::string &more_info_link =
-		service["more_info_link"].string_value();
-
-	if (more_info_link.empty()) {
-		ui_moreInfoButton->hide();
-	} else {
-		ui_moreInfoButton->setTargetUrl(QUrl(more_info_link.c_str()));
-		ui_moreInfoButton->show();
-	}
-}
-
-void StreamSettingsUI::UpdateKeyLink()
-{
-	QString serviceName = ui_service->currentText();
-	QString customServer = ui_customServer->text().trimmed();
-
-	Json service = get_service_from_json(GetServicesJson(),
-					     QT_TO_UTF8(serviceName));
-
-	std::string streamKeyLink = service["stream_key_link"].string_value();
-	if (customServer.contains("fbcdn.net") && IsCustomService()) {
-		streamKeyLink =
-			"https://www.facebook.com/live/producer?ref=OBS";
-	}
-
-	if (serviceName == "Dacast") {
-		ui_streamKeyLabel->setText(
-			QTStr("Basic.AutoConfig.StreamPage.EncoderKey"));
-	} else {
-		ui_streamKeyLabel->setText(
-			QTStr("Basic.AutoConfig.StreamPage.StreamKey"));
-	}
-
-	if (streamKeyLink.empty()) {
-		ui_streamKeyButton->hide();
-	} else {
-		ui_streamKeyButton->setTargetUrl(QUrl(streamKeyLink.c_str()));
-		ui_streamKeyButton->show();
-	}
-}
-
-void StreamSettingsUI::LoadServices(bool showAll)
-{
-	auto &services = GetServicesJson()["services"].array_items();
-
-	ui_service->blockSignals(true);
-	ui_service->clear();
-
-	QStringList names;
-
-	for (const Json &service : services) {
-		if (!showAll && !service["common"].bool_value())
-			continue;
-		names.push_back(service["name"].string_value().c_str());
-	}
-
-	if (showAll)
-		names.sort(Qt::CaseInsensitive);
-
-	for (QString &name : names)
-		ui_service->addItem(name);
-
-	if (!showAll) {
-		ui_service->addItem(
-			QTStr("Basic.AutoConfig.StreamPage.Service.ShowAll"),
-			QVariant((int)ListOpt::ShowAll));
-	}
-
-	ui_service->insertItem(
-		0, QTStr("Basic.AutoConfig.StreamPage.Service.Custom"),
-		QVariant((int)ListOpt::Custom));
-
-	if (!lastService.isEmpty()) {
-		int idx = ui_service->findText(lastService);
-		if (idx != -1)
-			ui_service->setCurrentIndex(idx);
-	}
-
-	ui_service->blockSignals(false);
-}
-
-void StreamSettingsUI::UpdateServerList()
-{
-	QString serviceName = ui_service->currentText();
-	bool showMore = ui_service->currentData().toInt() ==
-			(int)ListOpt::ShowAll;
-
-	if (showMore) {
-		LoadServices(true);
-		ui_service->showPopup();
-		return;
-	} else {
-		lastService = serviceName;
-	}
-
-	Json service = get_service_from_json(GetServicesJson(),
-					     QT_TO_UTF8(serviceName));
-
-	ui_server->clear();
-
-	auto &servers = service["servers"].array_items();
-	for (const Json &entry : servers) {
-		ui_server->addItem(entry["name"].string_value().c_str(),
-				   entry["url"].string_value().c_str());
-	}
-}

+ 0 - 73
UI/streaming-helpers.hpp

@@ -1,73 +0,0 @@
-#pragma once
-
-#include "url-push-button.hpp"
-#include <QComboBox>
-#include <QLineEdit>
-#include <QLabel>
-
-#include <json11.hpp>
-
-extern json11::Json get_services_json();
-extern json11::Json get_service_from_json(const json11::Json &root,
-					  const char *name);
-
-enum class ListOpt : int {
-	ShowAll = 1,
-	Custom,
-};
-
-class StreamSettingsUI : public QObject {
-	Q_OBJECT
-
-	QLabel *ui_streamKeyLabel;
-	QComboBox *ui_service;
-	QComboBox *ui_server;
-	QLineEdit *ui_customServer;
-	UrlPushButton *ui_moreInfoButton;
-	UrlPushButton *ui_streamKeyButton;
-
-	json11::Json servicesRoot;
-	bool servicesLoaded = false;
-	QString lastService;
-
-public:
-	inline void Setup(QLabel *streamKeyLabel, QComboBox *service,
-			  QComboBox *server, QLineEdit *customServer,
-			  UrlPushButton *moreInfoButton,
-			  UrlPushButton *streamKeyButton)
-	{
-		ui_streamKeyLabel = streamKeyLabel;
-		ui_service = service;
-		ui_server = server;
-		ui_customServer = customServer;
-		ui_moreInfoButton = moreInfoButton;
-		ui_streamKeyButton = streamKeyButton;
-	}
-
-	inline bool IsCustomService() const
-	{
-		return ui_service->currentData().toInt() ==
-		       (int)ListOpt::Custom;
-	}
-
-	inline void ClearLastService() { lastService.clear(); }
-
-	inline json11::Json GetServicesJson()
-	{
-		if (!servicesLoaded && servicesRoot.is_null()) {
-			servicesRoot = get_services_json();
-			servicesLoaded = true;
-		}
-		return servicesRoot;
-	}
-
-	inline const QString &LastService() const { return lastService; }
-
-	bool IsServiceOutputHasNetworkFeatures();
-
-public slots:
-	void UpdateMoreInfoLink();
-	void UpdateKeyLink();
-	void LoadServices(bool showAll);
-	void UpdateServerList();
-};

+ 17 - 9
UI/window-basic-auto-config-test.cpp

@@ -19,7 +19,6 @@
 #define wiz reinterpret_cast<AutoConfig *>(wizard())
 
 using namespace std;
-using namespace json11;
 
 /* ------------------------------------------------------------------------- */
 
@@ -120,19 +119,28 @@ void AutoConfigTestPage::StartRecordingEncoderStage()
 
 void AutoConfigTestPage::GetServers(std::vector<ServerInfo> &servers)
 {
-	Json root = get_services_json();
-	Json service = get_service_from_json(root, wiz->serviceName.c_str());
+	OBSDataAutoRelease settings = obs_data_create();
+	obs_data_set_string(settings, "service", wiz->serviceName.c_str());
 
-	auto &json_services = service["servers"].array_items();
-	for (const Json &server : json_services) {
-		const std::string &name = server["name"].string_value();
-		const std::string &url = server["url"].string_value();
+	obs_properties_t *ppts = obs_get_service_properties("rtmp_common");
+	obs_property_t *p = obs_properties_get(ppts, "service");
+	obs_property_modified(p, settings);
 
-		if (wiz->CanTestServer(name.c_str())) {
-			ServerInfo info(name, url);
+	p = obs_properties_get(ppts, "server");
+	size_t count = obs_property_list_item_count(p);
+	servers.reserve(count);
+
+	for (size_t i = 0; i < count; i++) {
+		const char *name = obs_property_list_item_name(p, i);
+		const char *server = obs_property_list_item_string(p, i);
+
+		if (wiz->CanTestServer(name)) {
+			ServerInfo info(name, server);
 			servers.push_back(info);
 		}
 	}
+
+	obs_properties_destroy(ppts);
 }
 
 static inline void string_depad_key(string &key)

+ 190 - 25
UI/window-basic-auto-config.cpp

@@ -23,8 +23,6 @@
 #include "youtube-api-wrappers.hpp"
 #endif
 
-using namespace json11;
-
 struct QCef;
 struct QCefCookieManager;
 
@@ -242,6 +240,11 @@ bool AutoConfigVideoPage::validatePage()
 
 /* ------------------------------------------------------------------------- */
 
+enum class ListOpt : int {
+	ShowAll = 1,
+	Custom,
+};
+
 AutoConfigStreamPage::AutoConfigStreamPage(QWidget *parent)
 	: QWizardPage(parent), ui(new Ui_AutoConfigStreamPage)
 {
@@ -251,10 +254,6 @@ AutoConfigStreamPage::AutoConfigStreamPage(QWidget *parent)
 	ui->connectAccount2->setVisible(false);
 	ui->disconnectAccount->setVisible(false);
 
-	streamUi.Setup(ui->streamKeyLabel, ui->service, ui->server,
-		       ui->customServer, ui->moreInfoButton,
-		       ui->streamKeyButton);
-
 	ui->connectedAccountLabel->setVisible(false);
 	ui->connectedAccountText->setVisible(false);
 
@@ -275,25 +274,25 @@ AutoConfigStreamPage::AutoConfigStreamPage(QWidget *parent)
 	setTitle(QTStr("Basic.AutoConfig.StreamPage"));
 	setSubTitle(QTStr("Basic.AutoConfig.StreamPage.SubTitle"));
 
-	streamUi.LoadServices(false);
+	LoadServices(false);
 
 	connect(ui->service, SIGNAL(currentIndexChanged(int)), this,
 		SLOT(ServiceChanged()));
 	connect(ui->customServer, SIGNAL(textChanged(const QString &)), this,
 		SLOT(ServiceChanged()));
-	connect(ui->customServer, SIGNAL(textChanged(const QString &)),
-		&streamUi, SLOT(UpdateKeyLink()));
-	connect(ui->customServer, SIGNAL(editingFinished()), &streamUi,
+	connect(ui->customServer, SIGNAL(textChanged(const QString &)), this,
+		SLOT(UpdateKeyLink()));
+	connect(ui->customServer, SIGNAL(editingFinished()), this,
 		SLOT(UpdateKeyLink()));
 	connect(ui->doBandwidthTest, SIGNAL(toggled(bool)), this,
 		SLOT(ServiceChanged()));
 
-	connect(ui->service, SIGNAL(currentIndexChanged(int)), &streamUi,
+	connect(ui->service, SIGNAL(currentIndexChanged(int)), this,
 		SLOT(UpdateServerList()));
 
-	connect(ui->service, SIGNAL(currentIndexChanged(int)), &streamUi,
+	connect(ui->service, SIGNAL(currentIndexChanged(int)), this,
 		SLOT(UpdateKeyLink()));
-	connect(ui->service, SIGNAL(currentIndexChanged(int)), &streamUi,
+	connect(ui->service, SIGNAL(currentIndexChanged(int)), this,
 		SLOT(UpdateMoreInfoLink()));
 
 	connect(ui->useStreamKeyAdv, &QPushButton::clicked, this,
@@ -323,11 +322,16 @@ int AutoConfigStreamPage::nextId() const
 	return AutoConfig::TestPage;
 }
 
+inline bool AutoConfigStreamPage::IsCustomService() const
+{
+	return ui->service->currentData().toInt() == (int)ListOpt::Custom;
+}
+
 bool AutoConfigStreamPage::validatePage()
 {
 	OBSDataAutoRelease service_settings = obs_data_create();
 
-	wiz->customServer = streamUi.IsCustomService();
+	wiz->customServer = IsCustomService();
 
 	const char *serverType = wiz->customServer ? "rtmp_custom"
 						   : "rtmp_common";
@@ -538,7 +542,7 @@ void AutoConfigStreamPage::on_disconnectAccount_clicked()
 	ui->connectedAccountText->setVisible(false);
 
 	/* Restore key link when disconnecting account */
-	streamUi.UpdateKeyLink();
+	UpdateKeyLink();
 }
 
 void AutoConfigStreamPage::on_useStreamKey_clicked()
@@ -611,7 +615,7 @@ void AutoConfigStreamPage::ServiceChanged()
 	std::string service = QT_TO_UTF8(ui->service->currentText());
 	bool regionBased = service == "Twitch";
 	bool testBandwidth = ui->doBandwidthTest->isChecked();
-	bool custom = streamUi.IsCustomService();
+	bool custom = IsCustomService();
 
 	reset_service_ui_fields(service);
 
@@ -668,13 +672,166 @@ void AutoConfigStreamPage::ServiceChanged()
 	UpdateCompleted();
 }
 
+void AutoConfigStreamPage::UpdateMoreInfoLink()
+{
+	if (IsCustomService()) {
+		ui->moreInfoButton->hide();
+		return;
+	}
+
+	QString serviceName = ui->service->currentText();
+	obs_properties_t *props = obs_get_service_properties("rtmp_common");
+	obs_property_t *services = obs_properties_get(props, "service");
+
+	OBSDataAutoRelease settings = obs_data_create();
+
+	obs_data_set_string(settings, "service", QT_TO_UTF8(serviceName));
+	obs_property_modified(services, settings);
+
+	const char *more_info_link =
+		obs_data_get_string(settings, "more_info_link");
+
+	if (!more_info_link || (*more_info_link == '\0')) {
+		ui->moreInfoButton->hide();
+	} else {
+		ui->moreInfoButton->setTargetUrl(QUrl(more_info_link));
+		ui->moreInfoButton->show();
+	}
+	obs_properties_destroy(props);
+}
+
+void AutoConfigStreamPage::UpdateKeyLink()
+{
+	QString serviceName = ui->service->currentText();
+	QString customServer = ui->customServer->text().trimmed();
+	QString streamKeyLink;
+
+	obs_properties_t *props = obs_get_service_properties("rtmp_common");
+	obs_property_t *services = obs_properties_get(props, "service");
+
+	OBSDataAutoRelease settings = obs_data_create();
+
+	obs_data_set_string(settings, "service", QT_TO_UTF8(serviceName));
+	obs_property_modified(services, settings);
+
+	streamKeyLink = obs_data_get_string(settings, "stream_key_link");
+
+	if (customServer.contains("fbcdn.net") && IsCustomService()) {
+		streamKeyLink =
+			"https://www.facebook.com/live/producer?ref=OBS";
+	}
+
+	if (serviceName == "Dacast") {
+		ui->streamKeyLabel->setText(
+			QTStr("Basic.AutoConfig.StreamPage.EncoderKey"));
+	} else {
+		ui->streamKeyLabel->setText(
+			QTStr("Basic.AutoConfig.StreamPage.StreamKey"));
+	}
+
+	if (QString(streamKeyLink).isNull() ||
+	    QString(streamKeyLink).isEmpty()) {
+		ui->streamKeyButton->hide();
+	} else {
+		ui->streamKeyButton->setTargetUrl(QUrl(streamKeyLink));
+		ui->streamKeyButton->show();
+	}
+	obs_properties_destroy(props);
+}
+
+void AutoConfigStreamPage::LoadServices(bool showAll)
+{
+	obs_properties_t *props = obs_get_service_properties("rtmp_common");
+
+	OBSDataAutoRelease settings = obs_data_create();
+
+	obs_data_set_bool(settings, "show_all", showAll);
+
+	obs_property_t *prop = obs_properties_get(props, "show_all");
+	obs_property_modified(prop, settings);
+
+	ui->service->blockSignals(true);
+	ui->service->clear();
+
+	QStringList names;
+
+	obs_property_t *services = obs_properties_get(props, "service");
+	size_t services_count = obs_property_list_item_count(services);
+	for (size_t i = 0; i < services_count; i++) {
+		const char *name = obs_property_list_item_string(services, i);
+		names.push_back(name);
+	}
+
+	if (showAll)
+		names.sort(Qt::CaseInsensitive);
+
+	for (QString &name : names)
+		ui->service->addItem(name);
+
+	if (!showAll) {
+		ui->service->addItem(
+			QTStr("Basic.AutoConfig.StreamPage.Service.ShowAll"),
+			QVariant((int)ListOpt::ShowAll));
+	}
+
+	ui->service->insertItem(
+		0, QTStr("Basic.AutoConfig.StreamPage.Service.Custom"),
+		QVariant((int)ListOpt::Custom));
+
+	if (!lastService.isEmpty()) {
+		int idx = ui->service->findText(lastService);
+		if (idx != -1)
+			ui->service->setCurrentIndex(idx);
+	}
+
+	obs_properties_destroy(props);
+
+	ui->service->blockSignals(false);
+}
+
+void AutoConfigStreamPage::UpdateServerList()
+{
+	QString serviceName = ui->service->currentText();
+	bool showMore = ui->service->currentData().toInt() ==
+			(int)ListOpt::ShowAll;
+
+	if (showMore) {
+		LoadServices(true);
+		ui->service->showPopup();
+		return;
+	} else {
+		lastService = serviceName;
+	}
+
+	obs_properties_t *props = obs_get_service_properties("rtmp_common");
+	obs_property_t *services = obs_properties_get(props, "service");
+
+	OBSDataAutoRelease settings = obs_data_create();
+
+	obs_data_set_string(settings, "service", QT_TO_UTF8(serviceName));
+	obs_property_modified(services, settings);
+
+	obs_property_t *servers = obs_properties_get(props, "server");
+
+	ui->server->clear();
+
+	size_t servers_count = obs_property_list_item_count(servers);
+	for (size_t i = 0; i < servers_count; i++) {
+		const char *name = obs_property_list_item_name(servers, i);
+		const char *server = obs_property_list_item_string(servers, i);
+		ui->server->addItem(name, server);
+	}
+
+	obs_properties_destroy(props);
+}
+
 void AutoConfigStreamPage::UpdateCompleted()
 {
 	if (ui->stackedWidget->currentIndex() == (int)Section::Connect ||
 	    (ui->key->text().isEmpty() && !auth)) {
 		ready = false;
 	} else {
-		bool custom = streamUi.IsCustomService();
+		bool custom = IsCustomService();
 		if (custom) {
 			ready = !ui->customServer->text().isEmpty();
 		} else {
@@ -729,10 +886,18 @@ AutoConfig::AutoConfig(QWidget *parent) : QWizard(parent)
 	/* ----------------------------------------- */
 	/* check to see if Twitch's "auto" available */
 
-	Json servicesRoot = get_services_json();
-	Json serviceJson = get_service_from_json(servicesRoot, "Twitch");
-	Json servers = serviceJson["servers"];
-	twitchAuto = servers[0]["url"].string_value() == "auto";
+	OBSDataAutoRelease twitchSettings = obs_data_create();
+
+	obs_data_set_string(twitchSettings, "service", "Twitch");
+
+	obs_properties_t *props = obs_get_service_properties("rtmp_common");
+	obs_properties_apply_settings(props, twitchSettings);
+
+	obs_property_t *p = obs_properties_get(props, "server");
+	const char *first = obs_property_list_item_string(p, 0);
+	twitchAuto = strcmp(first, "auto") == 0;
+
+	obs_properties_destroy(props);
 
 	/* ----------------------------------------- */
 	/* load service/servers                      */
@@ -765,10 +930,10 @@ AutoConfig::AutoConfig(QWidget *parent) : QWizard(parent)
 		serviceList->blockSignals(false);
 	}
 
-	streamPage->streamUi.UpdateServerList();
-	streamPage->streamUi.UpdateKeyLink();
-	streamPage->streamUi.UpdateMoreInfoLink();
-	streamPage->streamUi.ClearLastService();
+	streamPage->UpdateServerList();
+	streamPage->UpdateKeyLink();
+	streamPage->UpdateMoreInfoLink();
+	streamPage->lastService.clear();
 
 	if (!customServer) {
 		QComboBox *serverList = streamPage->ui->server;

+ 7 - 7
UI/window-basic-auto-config.hpp

@@ -13,10 +13,6 @@
 #include <string>
 #include <mutex>
 
-#include <json11.hpp>
-
-#include "streaming-helpers.hpp"
-
 class Ui_AutoConfigStartPage;
 class Ui_AutoConfigVideoPage;
 class Ui_AutoConfigStreamPage;
@@ -175,9 +171,11 @@ class AutoConfigStreamPage : public QWizardPage {
 	std::shared_ptr<Auth> auth;
 
 	std::unique_ptr<Ui_AutoConfigStreamPage> ui;
+	QString lastService;
 	bool ready = false;
 
-	StreamSettingsUI streamUi;
+	void LoadServices(bool showAll);
+	inline bool IsCustomService() const;
 
 public:
 	AutoConfigStreamPage(QWidget *parent = nullptr);
@@ -196,6 +194,9 @@ public slots:
 	void on_disconnectAccount_clicked();
 	void on_useStreamKey_clicked();
 	void ServiceChanged();
+	void UpdateKeyLink();
+	void UpdateMoreInfoLink();
+	void UpdateServerList();
 	void UpdateCompleted();
 
 	void reset_service_ui_fields(std::string &service);
@@ -247,8 +248,7 @@ class AutoConfigTestPage : public QWizardPage {
 
 		inline ServerInfo() {}
 
-		inline ServerInfo(const std::string &name_,
-				  const std::string &address_)
+		inline ServerInfo(const char *name_, const char *address_)
 			: name(name_), address(address_)
 		{
 		}

+ 182 - 30
UI/window-basic-settings-stream.cpp

@@ -20,19 +20,27 @@
 #include "youtube-api-wrappers.hpp"
 #endif
 
-using namespace json11;
-
 struct QCef;
 struct QCefCookieManager;
 
 extern QCef *cef;
 extern QCefCookieManager *panel_cookies;
 
+enum class ListOpt : int {
+	ShowAll = 1,
+	Custom,
+};
+
 enum class Section : int {
 	Connect,
 	StreamKey,
 };
 
+inline bool OBSBasicSettings::IsCustomService() const
+{
+	return ui->service->currentData().toInt() == (int)ListOpt::Custom;
+}
+
 void OBSBasicSettings::InitStreamPage()
 {
 	ui->connectAccount2->setVisible(false);
@@ -59,11 +67,7 @@ void OBSBasicSettings::InitStreamPage()
 	m.setTop(vertSpacing / 2);
 	ui->streamkeyPageLayout->setContentsMargins(m);
 
-	streamUi.Setup(ui->streamKeyLabel, ui->service, ui->server,
-		       ui->customServer, ui->moreInfoButton,
-		       ui->getStreamKeyButton);
-
-	streamUi.LoadServices(false);
+	LoadServices(false);
 
 	ui->twitchAddonDropdown->addItem(
 		QTStr("Basic.Settings.Stream.TTVAddon.None"));
@@ -74,9 +78,9 @@ void OBSBasicSettings::InitStreamPage()
 	ui->twitchAddonDropdown->addItem(
 		QTStr("Basic.Settings.Stream.TTVAddon.Both"));
 
-	connect(ui->service, SIGNAL(currentIndexChanged(int)), &streamUi,
+	connect(ui->service, SIGNAL(currentIndexChanged(int)), this,
 		SLOT(UpdateServerList()));
-	connect(ui->service, SIGNAL(currentIndexChanged(int)), &streamUi,
+	connect(ui->service, SIGNAL(currentIndexChanged(int)), this,
 		SLOT(UpdateKeyLink()));
 	connect(ui->service, SIGNAL(currentIndexChanged(int)), this,
 		SLOT(UpdateVodTrackSetting()));
@@ -84,19 +88,14 @@ void OBSBasicSettings::InitStreamPage()
 		SLOT(UpdateServiceRecommendations()));
 	connect(ui->service, SIGNAL(currentIndexChanged(int)), this,
 		SLOT(UpdateResFPSLimits()));
-	connect(ui->customServer, SIGNAL(textChanged(const QString &)),
-		&streamUi, SLOT(UpdateKeyLink()));
+	connect(ui->customServer, SIGNAL(textChanged(const QString &)), this,
+		SLOT(UpdateKeyLink()));
 	connect(ui->ignoreRecommended, SIGNAL(clicked(bool)), this,
 		SLOT(DisplayEnforceWarning(bool)));
 	connect(ui->ignoreRecommended, SIGNAL(toggled(bool)), this,
 		SLOT(UpdateResFPSLimits()));
-	connect(ui->service, SIGNAL(currentIndexChanged(int)), &streamUi,
-		SLOT(UpdateMoreInfoLink()));
-
 	connect(ui->service, SIGNAL(currentIndexChanged(int)), this,
-		SLOT(UpdateAdvNetworkGroup()));
-	connect(ui->customServer, SIGNAL(textChanged(const QString &)), this,
-		SLOT(UpdateAdvNetworkGroup()));
+		SLOT(UpdateMoreInfoLink()));
 }
 
 void OBSBasicSettings::LoadStream1Settings()
@@ -143,7 +142,7 @@ void OBSBasicSettings::LoadStream1Settings()
 		ui->twitchAddonDropdown->setCurrentIndex(idx);
 	}
 
-	streamUi.UpdateServerList();
+	UpdateServerList();
 
 	if (strcmp(type, "rtmp_common") == 0) {
 		int idx = ui->server->findData(server);
@@ -157,11 +156,11 @@ void OBSBasicSettings::LoadStream1Settings()
 
 	ui->key->setText(key);
 
-	streamUi.ClearLastService();
+	lastService.clear();
 	on_service_currentIndexChanged(0);
 
-	streamUi.UpdateKeyLink();
-	streamUi.UpdateMoreInfoLink();
+	UpdateKeyLink();
+	UpdateMoreInfoLink();
 	UpdateVodTrackSetting();
 	UpdateServiceRecommendations();
 
@@ -178,7 +177,7 @@ void OBSBasicSettings::LoadStream1Settings()
 
 void OBSBasicSettings::SaveStream1Settings()
 {
-	bool customServer = streamUi.IsCustomService();
+	bool customServer = IsCustomService();
 	const char *service_id = customServer ? "rtmp_custom" : "rtmp_common";
 
 	obs_service_t *oldService = main->GetService();
@@ -247,6 +246,123 @@ void OBSBasicSettings::SaveStream1Settings()
 	SaveCheckBox(ui->ignoreRecommended, "Stream1", "IgnoreRecommended");
 }
 
+void OBSBasicSettings::UpdateMoreInfoLink()
+{
+	if (IsCustomService()) {
+		ui->moreInfoButton->hide();
+		return;
+	}
+
+	QString serviceName = ui->service->currentText();
+	obs_properties_t *props = obs_get_service_properties("rtmp_common");
+	obs_property_t *services = obs_properties_get(props, "service");
+
+	OBSDataAutoRelease settings = obs_data_create();
+
+	obs_data_set_string(settings, "service", QT_TO_UTF8(serviceName));
+	obs_property_modified(services, settings);
+
+	const char *more_info_link =
+		obs_data_get_string(settings, "more_info_link");
+
+	if (!more_info_link || (*more_info_link == '\0')) {
+		ui->moreInfoButton->hide();
+	} else {
+		ui->moreInfoButton->setTargetUrl(QUrl(more_info_link));
+		ui->moreInfoButton->show();
+	}
+	obs_properties_destroy(props);
+}
+
+void OBSBasicSettings::UpdateKeyLink()
+{
+	QString serviceName = ui->service->currentText();
+	QString customServer = ui->customServer->text().trimmed();
+	QString streamKeyLink;
+
+	obs_properties_t *props = obs_get_service_properties("rtmp_common");
+	obs_property_t *services = obs_properties_get(props, "service");
+
+	OBSDataAutoRelease settings = obs_data_create();
+
+	obs_data_set_string(settings, "service", QT_TO_UTF8(serviceName));
+	obs_property_modified(services, settings);
+
+	streamKeyLink = obs_data_get_string(settings, "stream_key_link");
+
+	if (customServer.contains("fbcdn.net") && IsCustomService()) {
+		streamKeyLink =
+			"https://www.facebook.com/live/producer?ref=OBS";
+	}
+
+	if (serviceName == "Dacast") {
+		ui->streamKeyLabel->setText(
+			QTStr("Basic.AutoConfig.StreamPage.EncoderKey"));
+	} else {
+		ui->streamKeyLabel->setText(
+			QTStr("Basic.AutoConfig.StreamPage.StreamKey"));
+	}
+
+	if (QString(streamKeyLink).isNull() ||
+	    QString(streamKeyLink).isEmpty()) {
+		ui->getStreamKeyButton->hide();
+	} else {
+		ui->getStreamKeyButton->setTargetUrl(QUrl(streamKeyLink));
+		ui->getStreamKeyButton->show();
+	}
+	obs_properties_destroy(props);
+}
+
+void OBSBasicSettings::LoadServices(bool showAll)
+{
+	obs_properties_t *props = obs_get_service_properties("rtmp_common");
+
+	OBSDataAutoRelease settings = obs_data_create();
+
+	obs_data_set_bool(settings, "show_all", showAll);
+
+	obs_property_t *prop = obs_properties_get(props, "show_all");
+	obs_property_modified(prop, settings);
+
+	ui->service->blockSignals(true);
+	ui->service->clear();
+
+	QStringList names;
+
+	obs_property_t *services = obs_properties_get(props, "service");
+	size_t services_count = obs_property_list_item_count(services);
+	for (size_t i = 0; i < services_count; i++) {
+		const char *name = obs_property_list_item_string(services, i);
+		names.push_back(name);
+	}
+
+	if (showAll)
+		names.sort(Qt::CaseInsensitive);
+
+	for (QString &name : names)
+		ui->service->addItem(name);
+
+	if (!showAll) {
+		ui->service->addItem(
+			QTStr("Basic.AutoConfig.StreamPage.Service.ShowAll"),
+			QVariant((int)ListOpt::ShowAll));
+	}
+
+	ui->service->insertItem(
+		0, QTStr("Basic.AutoConfig.StreamPage.Service.Custom"),
+		QVariant((int)ListOpt::Custom));
+
+	if (!lastService.isEmpty()) {
+		int idx = ui->service->findText(lastService);
+		if (idx != -1)
+			ui->service->setCurrentIndex(idx);
+	}
+
+	obs_properties_destroy(props);
+
+	ui->service->blockSignals(false);
+}
+
 static inline bool is_auth_service(const std::string &service)
 {
 	return Auth::AuthType(service) != Auth::Type::None;
@@ -319,14 +435,14 @@ void OBSBasicSettings::on_service_currentIndexChanged(int)
 		return;
 
 	std::string service = QT_TO_UTF8(ui->service->currentText());
-	bool custom = streamUi.IsCustomService();
+	bool custom = IsCustomService();
 
 	ui->disconnectAccount->setVisible(false);
 	ui->bandwidthTestEnable->setVisible(false);
 	ui->twitchAddonDropdown->setVisible(false);
 	ui->twitchAddonLabel->setVisible(false);
 
-	if (streamUi.LastService() != service.c_str()) {
+	if (lastService != service.c_str()) {
 		reset_service_ui_fields(ui.get(), service, loading);
 	}
 
@@ -368,6 +484,42 @@ void OBSBasicSettings::on_service_currentIndexChanged(int)
 	}
 }
 
+void OBSBasicSettings::UpdateServerList()
+{
+	QString serviceName = ui->service->currentText();
+	bool showMore = ui->service->currentData().toInt() ==
+			(int)ListOpt::ShowAll;
+
+	if (showMore) {
+		LoadServices(true);
+		ui->service->showPopup();
+		return;
+	} else {
+		lastService = serviceName;
+	}
+
+	obs_properties_t *props = obs_get_service_properties("rtmp_common");
+	obs_property_t *services = obs_properties_get(props, "service");
+
+	OBSDataAutoRelease settings = obs_data_create();
+
+	obs_data_set_string(settings, "service", QT_TO_UTF8(serviceName));
+	obs_property_modified(services, settings);
+
+	obs_property_t *servers = obs_properties_get(props, "server");
+
+	ui->server->clear();
+
+	size_t servers_count = obs_property_list_item_count(servers);
+	for (size_t i = 0; i < servers_count; i++) {
+		const char *name = obs_property_list_item_name(servers, i);
+		const char *server = obs_property_list_item_string(servers, i);
+		ui->server->addItem(name, server);
+	}
+
+	obs_properties_destroy(props);
+}
+
 void OBSBasicSettings::on_show_clicked()
 {
 	if (ui->key->echoMode() == QLineEdit::Password) {
@@ -392,7 +544,7 @@ void OBSBasicSettings::on_authPwShow_clicked()
 
 OBSService OBSBasicSettings::SpawnTempService()
 {
-	bool custom = streamUi.IsCustomService();
+	bool custom = IsCustomService();
 	const char *service_id = custom ? "rtmp_custom" : "rtmp_common";
 
 	OBSDataAutoRelease settings = obs_data_create();
@@ -535,7 +687,7 @@ void OBSBasicSettings::on_useStreamKey_clicked()
 
 void OBSBasicSettings::on_useAuth_toggled()
 {
-	if (!streamUi.IsCustomService())
+	if (!IsCustomService())
 		return;
 
 	bool use_auth = ui->useAuth->isChecked();
@@ -553,7 +705,7 @@ void OBSBasicSettings::UpdateVodTrackSetting()
 	bool enableVodTrack = ui->service->currentText() == "Twitch";
 	bool wasEnabled = !!vodTrackCheckbox;
 
-	if (enableForCustomServer && streamUi.IsCustomService())
+	if (enableForCustomServer && IsCustomService())
 		enableVodTrack = true;
 
 	if (enableVodTrack == wasEnabled)
@@ -640,7 +792,7 @@ OBSService OBSBasicSettings::GetStream1Service()
 
 void OBSBasicSettings::UpdateServiceRecommendations()
 {
-	bool customServer = streamUi.IsCustomService();
+	bool customServer = IsCustomService();
 	ui->ignoreRecommended->setVisible(!customServer);
 	ui->enforceSettingsLabel->setVisible(!customServer);
 
@@ -714,7 +866,7 @@ void OBSBasicSettings::UpdateServiceRecommendations()
 
 void OBSBasicSettings::DisplayEnforceWarning(bool checked)
 {
-	if (streamUi.IsCustomService())
+	if (IsCustomService())
 		return;
 
 	if (!checked) {
@@ -816,7 +968,7 @@ void OBSBasicSettings::UpdateResFPSLimits()
 	size_t res_count = 0;
 	int max_fps = 0;
 
-	if (!streamUi.IsCustomService() && !ignoreRecommended) {
+	if (!IsCustomService() && !ignoreRecommended) {
 		OBSService service = GetStream1Service();
 		obs_service_get_supported_resolutions(service, &res_list,
 						      &res_count);

+ 0 - 17
UI/window-basic-settings.cpp

@@ -934,8 +934,6 @@ OBSBasicSettings::OBSBasicSettings(QWidget *parent)
 
 	connect(ui->useStreamKeyAdv, SIGNAL(clicked()), this,
 		SLOT(UseStreamKeyAdvClicked()));
-
-	UpdateAdvNetworkGroup();
 }
 
 OBSBasicSettings::~OBSBasicSettings()
@@ -5422,18 +5420,3 @@ void OBSBasicSettings::RecreateOutputResolutionWidget()
 	ui->outputResolution->lineEdit()->setValidator(
 		ui->baseResolution->lineEdit()->validator());
 }
-
-void OBSBasicSettings::UpdateAdvNetworkGroup()
-{
-	bool enabled = streamUi.IsServiceOutputHasNetworkFeatures();
-
-	ui->advNetworkDisabled->setVisible(!enabled);
-
-	ui->bindToIPLabel->setVisible(enabled);
-	ui->bindToIP->setVisible(enabled);
-	ui->dynBitrate->setVisible(enabled);
-#ifdef _WIN32
-	ui->enableNewSocketLoop->setVisible(enabled);
-	ui->enableLowLatencyMode->setVisible(enabled);
-#endif
-}

+ 6 - 7
UI/window-basic-settings.hpp

@@ -28,7 +28,6 @@
 
 #include <obs.hpp>
 
-#include "streaming-helpers.hpp"
 #include "auth-base.hpp"
 
 class OBSBasic;
@@ -42,8 +41,6 @@ class OBSHotkeyWidget;
 
 #include "ui_OBSBasicSettings.h"
 
-#include <json11.hpp>
-
 #define VOLUME_METER_DECAY_FAST 23.53
 #define VOLUME_METER_DECAY_MEDIUM 11.76
 #define VOLUME_METER_DECAY_SLOW 8.57
@@ -162,8 +159,6 @@ private:
 	uint32_t outputCX = 0;
 	uint32_t outputCY = 0;
 
-	StreamSettingsUI streamUi;
-
 	QPointer<QCheckBox> simpleVodTrack;
 
 	QPointer<QCheckBox> vodTrackCheckbox;
@@ -254,15 +249,21 @@ private:
 
 	/* stream */
 	void InitStreamPage();
+	inline bool IsCustomService() const;
+	void LoadServices(bool showAll);
 	void OnOAuthStreamKeyConnected();
 	void OnAuthConnected();
+	QString lastService;
 	int prevLangIndex;
 	bool prevBrowserAccel;
 private slots:
+	void UpdateServerList();
+	void UpdateKeyLink();
 	void UpdateVodTrackSetting();
 	void UpdateServiceRecommendations();
 	void RecreateOutputResolutionWidget();
 	void UpdateResFPSLimits();
+	void UpdateMoreInfoLink();
 	void DisplayEnforceWarning(bool checked);
 	void on_show_clicked();
 	void on_authPwShow_clicked();
@@ -391,8 +392,6 @@ private slots:
 
 	void UpdateStreamDelayEstimate();
 
-	void UpdateAdvNetworkGroup();
-
 	void UpdateAutomaticReplayBufferCheckboxes();
 
 	void AdvOutSplitFileChanged();