AutoConfigStreamPage.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697
  1. #include "AutoConfigStreamPage.hpp"
  2. #include "AutoConfig.hpp"
  3. #include "ui_AutoConfigStreamPage.h"
  4. #include <oauth/OAuth.hpp>
  5. #include <utility/GoLiveAPI_Network.hpp>
  6. #include <utility/GoLiveAPI_PostData.hpp>
  7. #include <utility/MultitrackVideoError.hpp>
  8. #ifdef YOUTUBE_ENABLED
  9. #include <utility/YoutubeApiWrappers.hpp>
  10. #endif
  11. #include <widgets/OBSBasic.hpp>
  12. #include <qt-wrappers.hpp>
  13. #include "moc_AutoConfigStreamPage.cpp"
  14. enum class ListOpt : int {
  15. ShowAll = 1,
  16. Custom,
  17. };
  18. struct QCef;
  19. extern QCef *cef;
  20. #define wiz reinterpret_cast<AutoConfig *>(wizard())
  21. AutoConfigStreamPage::AutoConfigStreamPage(QWidget *parent) : QWizardPage(parent), ui(new Ui_AutoConfigStreamPage)
  22. {
  23. ui->setupUi(this);
  24. ui->bitrateLabel->setVisible(false);
  25. ui->bitrate->setVisible(false);
  26. ui->connectAccount2->setVisible(false);
  27. ui->disconnectAccount->setVisible(false);
  28. ui->useMultitrackVideo->setVisible(false);
  29. ui->connectedAccountLabel->setVisible(false);
  30. ui->connectedAccountText->setVisible(false);
  31. int vertSpacing = ui->topLayout->verticalSpacing();
  32. QMargins m = ui->topLayout->contentsMargins();
  33. m.setBottom(vertSpacing / 2);
  34. ui->topLayout->setContentsMargins(m);
  35. m = ui->loginPageLayout->contentsMargins();
  36. m.setTop(vertSpacing / 2);
  37. ui->loginPageLayout->setContentsMargins(m);
  38. m = ui->streamkeyPageLayout->contentsMargins();
  39. m.setTop(vertSpacing / 2);
  40. ui->streamkeyPageLayout->setContentsMargins(m);
  41. setTitle(QTStr("Basic.AutoConfig.StreamPage"));
  42. setSubTitle(QTStr("Basic.AutoConfig.StreamPage.SubTitle"));
  43. LoadServices(false);
  44. connect(ui->service, &QComboBox::currentIndexChanged, this, &AutoConfigStreamPage::ServiceChanged);
  45. connect(ui->customServer, &QLineEdit::textChanged, this, &AutoConfigStreamPage::ServiceChanged);
  46. connect(ui->customServer, &QLineEdit::textChanged, this, &AutoConfigStreamPage::UpdateKeyLink);
  47. connect(ui->customServer, &QLineEdit::editingFinished, this, &AutoConfigStreamPage::UpdateKeyLink);
  48. connect(ui->doBandwidthTest, &QCheckBox::toggled, this, &AutoConfigStreamPage::ServiceChanged);
  49. connect(ui->service, &QComboBox::currentIndexChanged, this, &AutoConfigStreamPage::UpdateServerList);
  50. connect(ui->service, &QComboBox::currentIndexChanged, this, &AutoConfigStreamPage::UpdateKeyLink);
  51. connect(ui->service, &QComboBox::currentIndexChanged, this, &AutoConfigStreamPage::UpdateMoreInfoLink);
  52. connect(ui->useStreamKeyAdv, &QPushButton::clicked, [&]() {
  53. ui->streamKeyWidget->setVisible(true);
  54. ui->streamKeyLabel->setVisible(true);
  55. ui->useStreamKeyAdv->setVisible(false);
  56. });
  57. connect(ui->key, &QLineEdit::textChanged, this, &AutoConfigStreamPage::UpdateCompleted);
  58. connect(ui->regionUS, &QCheckBox::toggled, this, &AutoConfigStreamPage::UpdateCompleted);
  59. connect(ui->regionEU, &QCheckBox::toggled, this, &AutoConfigStreamPage::UpdateCompleted);
  60. connect(ui->regionAsia, &QCheckBox::toggled, this, &AutoConfigStreamPage::UpdateCompleted);
  61. connect(ui->regionOther, &QCheckBox::toggled, this, &AutoConfigStreamPage::UpdateCompleted);
  62. }
  63. AutoConfigStreamPage::~AutoConfigStreamPage() {}
  64. bool AutoConfigStreamPage::isComplete() const
  65. {
  66. return ready;
  67. }
  68. int AutoConfigStreamPage::nextId() const
  69. {
  70. return AutoConfig::TestPage;
  71. }
  72. inline bool AutoConfigStreamPage::IsCustomService() const
  73. {
  74. return ui->service->currentData().toInt() == (int)ListOpt::Custom;
  75. }
  76. bool AutoConfigStreamPage::validatePage()
  77. {
  78. OBSDataAutoRelease service_settings = obs_data_create();
  79. wiz->customServer = IsCustomService();
  80. const char *serverType = wiz->customServer ? "rtmp_custom" : "rtmp_common";
  81. if (!wiz->customServer) {
  82. obs_data_set_string(service_settings, "service", QT_TO_UTF8(ui->service->currentText()));
  83. }
  84. OBSServiceAutoRelease service = obs_service_create(serverType, "temp_service", service_settings, nullptr);
  85. int bitrate;
  86. if (!ui->doBandwidthTest->isChecked()) {
  87. bitrate = ui->bitrate->value();
  88. wiz->idealBitrate = bitrate;
  89. } else {
  90. /* Default test target is 10 Mbps */
  91. bitrate = 10000;
  92. #ifdef YOUTUBE_ENABLED
  93. if (IsYouTubeService(wiz->serviceName)) {
  94. /* Adjust upper bound to YouTube limits
  95. * for resolutions above 1080p */
  96. if (wiz->baseResolutionCY > 1440)
  97. bitrate = 51000;
  98. else if (wiz->baseResolutionCY > 1080)
  99. bitrate = 18000;
  100. }
  101. #endif
  102. }
  103. OBSDataAutoRelease settings = obs_data_create();
  104. obs_data_set_int(settings, "bitrate", bitrate);
  105. obs_service_apply_encoder_settings(service, settings, nullptr);
  106. if (wiz->customServer) {
  107. QString server = ui->customServer->text().trimmed();
  108. wiz->server = wiz->serverName = QT_TO_UTF8(server);
  109. } else {
  110. wiz->serverName = QT_TO_UTF8(ui->server->currentText());
  111. wiz->server = QT_TO_UTF8(ui->server->currentData().toString());
  112. }
  113. wiz->bandwidthTest = ui->doBandwidthTest->isChecked();
  114. wiz->startingBitrate = (int)obs_data_get_int(settings, "bitrate");
  115. wiz->idealBitrate = wiz->startingBitrate;
  116. wiz->regionUS = ui->regionUS->isChecked();
  117. wiz->regionEU = ui->regionEU->isChecked();
  118. wiz->regionAsia = ui->regionAsia->isChecked();
  119. wiz->regionOther = ui->regionOther->isChecked();
  120. wiz->serviceName = QT_TO_UTF8(ui->service->currentText());
  121. if (ui->preferHardware)
  122. wiz->preferHardware = ui->preferHardware->isChecked();
  123. wiz->key = QT_TO_UTF8(ui->key->text());
  124. if (!wiz->customServer) {
  125. if (wiz->serviceName == "Twitch")
  126. wiz->service = AutoConfig::Service::Twitch;
  127. #ifdef YOUTUBE_ENABLED
  128. else if (IsYouTubeService(wiz->serviceName))
  129. wiz->service = AutoConfig::Service::YouTube;
  130. #endif
  131. else if (wiz->serviceName == "Amazon IVS")
  132. wiz->service = AutoConfig::Service::AmazonIVS;
  133. else
  134. wiz->service = AutoConfig::Service::Other;
  135. } else {
  136. wiz->service = AutoConfig::Service::Other;
  137. }
  138. if (wiz->service == AutoConfig::Service::Twitch) {
  139. wiz->testMultitrackVideo = ui->useMultitrackVideo->isChecked();
  140. if (wiz->testMultitrackVideo) {
  141. auto postData = constructGoLivePost(QString::fromStdString(wiz->key), std::nullopt,
  142. std::nullopt, false);
  143. OBSDataAutoRelease service_settings = obs_service_get_settings(service);
  144. auto multitrack_video_name = QTStr("Basic.Settings.Stream.MultitrackVideoLabel");
  145. if (obs_data_has_user_value(service_settings, "multitrack_video_name")) {
  146. multitrack_video_name = obs_data_get_string(service_settings, "multitrack_video_name");
  147. }
  148. try {
  149. auto config = DownloadGoLiveConfig(this, MultitrackVideoAutoConfigURL(service),
  150. postData, multitrack_video_name);
  151. for (const auto &endpoint : config.ingest_endpoints) {
  152. if (qstrnicmp("RTMP", endpoint.protocol.c_str(), 4) != 0)
  153. continue;
  154. std::string address = endpoint.url_template;
  155. auto pos = address.find("/{stream_key}");
  156. if (pos != address.npos)
  157. address.erase(pos);
  158. wiz->serviceConfigServers.push_back({address, address});
  159. }
  160. int multitrackVideoBitrate = 0;
  161. for (auto &encoder_config : config.encoder_configurations) {
  162. auto it = encoder_config.settings.find("bitrate");
  163. if (it == encoder_config.settings.end())
  164. continue;
  165. if (!it->is_number_integer())
  166. continue;
  167. int bitrate = 0;
  168. it->get_to(bitrate);
  169. multitrackVideoBitrate += bitrate;
  170. }
  171. if (multitrackVideoBitrate > 0) {
  172. wiz->startingBitrate = multitrackVideoBitrate;
  173. wiz->idealBitrate = multitrackVideoBitrate;
  174. wiz->multitrackVideo.targetBitrate = multitrackVideoBitrate;
  175. wiz->multitrackVideo.testSuccessful = true;
  176. }
  177. } catch (const MultitrackVideoError & /*err*/) {
  178. // FIXME: do something sensible
  179. }
  180. }
  181. }
  182. if (wiz->service != AutoConfig::Service::Twitch && wiz->service != AutoConfig::Service::YouTube &&
  183. wiz->service != AutoConfig::Service::AmazonIVS && wiz->bandwidthTest) {
  184. QMessageBox::StandardButton button;
  185. #define WARNING_TEXT(x) QTStr("Basic.AutoConfig.StreamPage.StreamWarning." x)
  186. button = OBSMessageBox::question(this, WARNING_TEXT("Title"), WARNING_TEXT("Text"));
  187. #undef WARNING_TEXT
  188. if (button == QMessageBox::No)
  189. return false;
  190. }
  191. return true;
  192. }
  193. void AutoConfigStreamPage::on_show_clicked()
  194. {
  195. if (ui->key->echoMode() == QLineEdit::Password) {
  196. ui->key->setEchoMode(QLineEdit::Normal);
  197. ui->show->setText(QTStr("Hide"));
  198. } else {
  199. ui->key->setEchoMode(QLineEdit::Password);
  200. ui->show->setText(QTStr("Show"));
  201. }
  202. }
  203. void AutoConfigStreamPage::OnOAuthStreamKeyConnected()
  204. {
  205. OAuthStreamKey *a = reinterpret_cast<OAuthStreamKey *>(auth.get());
  206. if (a) {
  207. bool validKey = !a->key().empty();
  208. if (validKey)
  209. ui->key->setText(QT_UTF8(a->key().c_str()));
  210. ui->streamKeyWidget->setVisible(false);
  211. ui->streamKeyLabel->setVisible(false);
  212. ui->connectAccount2->setVisible(false);
  213. ui->disconnectAccount->setVisible(true);
  214. ui->useStreamKeyAdv->setVisible(false);
  215. ui->connectedAccountLabel->setVisible(false);
  216. ui->connectedAccountText->setVisible(false);
  217. #ifdef YOUTUBE_ENABLED
  218. if (IsYouTubeService(a->service())) {
  219. ui->key->clear();
  220. ui->connectedAccountLabel->setVisible(true);
  221. ui->connectedAccountText->setVisible(true);
  222. ui->connectedAccountText->setText(QTStr("Auth.LoadingChannel.Title"));
  223. YoutubeApiWrappers *ytAuth = reinterpret_cast<YoutubeApiWrappers *>(a);
  224. ChannelDescription cd;
  225. if (ytAuth->GetChannelDescription(cd)) {
  226. ui->connectedAccountText->setText(cd.title);
  227. /* Create throwaway stream key for bandwidth test */
  228. if (ui->doBandwidthTest->isChecked()) {
  229. StreamDescription stream = {"", "", "OBS Studio Test Stream"};
  230. if (ytAuth->InsertStream(stream)) {
  231. ui->key->setText(stream.name);
  232. }
  233. }
  234. }
  235. }
  236. #endif
  237. }
  238. ui->stackedWidget->setCurrentIndex((int)Section::StreamKey);
  239. UpdateCompleted();
  240. }
  241. void AutoConfigStreamPage::OnAuthConnected()
  242. {
  243. std::string service = QT_TO_UTF8(ui->service->currentText());
  244. Auth::Type type = Auth::AuthType(service);
  245. if (type == Auth::Type::OAuth_StreamKey || type == Auth::Type::OAuth_LinkedAccount) {
  246. OnOAuthStreamKeyConnected();
  247. }
  248. }
  249. void AutoConfigStreamPage::on_connectAccount_clicked()
  250. {
  251. std::string service = QT_TO_UTF8(ui->service->currentText());
  252. OAuth::DeleteCookies(service);
  253. auth = OAuthStreamKey::Login(this, service);
  254. if (!!auth) {
  255. OnAuthConnected();
  256. ui->useStreamKeyAdv->setVisible(false);
  257. }
  258. }
  259. #define DISCONNECT_COMFIRM_TITLE "Basic.AutoConfig.StreamPage.DisconnectAccount.Confirm.Title"
  260. #define DISCONNECT_COMFIRM_TEXT "Basic.AutoConfig.StreamPage.DisconnectAccount.Confirm.Text"
  261. void AutoConfigStreamPage::on_disconnectAccount_clicked()
  262. {
  263. QMessageBox::StandardButton button;
  264. button = OBSMessageBox::question(this, QTStr(DISCONNECT_COMFIRM_TITLE), QTStr(DISCONNECT_COMFIRM_TEXT));
  265. if (button == QMessageBox::No) {
  266. return;
  267. }
  268. OBSBasic *main = OBSBasic::Get();
  269. main->auth.reset();
  270. auth.reset();
  271. std::string service = QT_TO_UTF8(ui->service->currentText());
  272. #ifdef BROWSER_AVAILABLE
  273. OAuth::DeleteCookies(service);
  274. #endif
  275. reset_service_ui_fields(service);
  276. ui->streamKeyWidget->setVisible(true);
  277. ui->streamKeyLabel->setVisible(true);
  278. ui->key->setText("");
  279. ui->connectedAccountLabel->setVisible(false);
  280. ui->connectedAccountText->setVisible(false);
  281. /* Restore key link when disconnecting account */
  282. UpdateKeyLink();
  283. }
  284. void AutoConfigStreamPage::on_useStreamKey_clicked()
  285. {
  286. ui->stackedWidget->setCurrentIndex((int)Section::StreamKey);
  287. UpdateCompleted();
  288. }
  289. void AutoConfigStreamPage::on_preferHardware_clicked()
  290. {
  291. auto *main = OBSBasic::Get();
  292. bool multitrackVideoEnabled = config_has_user_value(main->Config(), "Stream1", "EnableMultitrackVideo")
  293. ? config_get_bool(main->Config(), "Stream1", "EnableMultitrackVideo")
  294. : true;
  295. ui->useMultitrackVideo->setEnabled(ui->preferHardware->isChecked());
  296. ui->multitrackVideoInfo->setEnabled(ui->preferHardware->isChecked());
  297. ui->useMultitrackVideo->setChecked(ui->preferHardware->isChecked() && multitrackVideoEnabled);
  298. }
  299. static inline bool is_auth_service(const std::string &service)
  300. {
  301. return Auth::AuthType(service) != Auth::Type::None;
  302. }
  303. static inline bool is_external_oauth(const std::string &service)
  304. {
  305. return Auth::External(service);
  306. }
  307. void AutoConfigStreamPage::reset_service_ui_fields(std::string &service)
  308. {
  309. #ifdef YOUTUBE_ENABLED
  310. // when account is already connected:
  311. OAuthStreamKey *a = reinterpret_cast<OAuthStreamKey *>(auth.get());
  312. if (a && service == a->service() && IsYouTubeService(a->service())) {
  313. ui->connectedAccountLabel->setVisible(true);
  314. ui->connectedAccountText->setVisible(true);
  315. ui->connectAccount2->setVisible(false);
  316. ui->disconnectAccount->setVisible(true);
  317. return;
  318. }
  319. #endif
  320. bool external_oauth = is_external_oauth(service);
  321. if (external_oauth) {
  322. ui->streamKeyWidget->setVisible(false);
  323. ui->streamKeyLabel->setVisible(false);
  324. ui->connectAccount2->setVisible(true);
  325. ui->useStreamKeyAdv->setVisible(true);
  326. ui->stackedWidget->setCurrentIndex((int)Section::StreamKey);
  327. } else if (cef) {
  328. QString key = ui->key->text();
  329. bool can_auth = is_auth_service(service);
  330. int page = can_auth && key.isEmpty() ? (int)Section::Connect : (int)Section::StreamKey;
  331. ui->stackedWidget->setCurrentIndex(page);
  332. ui->streamKeyWidget->setVisible(true);
  333. ui->streamKeyLabel->setVisible(true);
  334. ui->connectAccount2->setVisible(can_auth);
  335. ui->useStreamKeyAdv->setVisible(false);
  336. } else {
  337. ui->connectAccount2->setVisible(false);
  338. ui->useStreamKeyAdv->setVisible(false);
  339. }
  340. ui->connectedAccountLabel->setVisible(false);
  341. ui->connectedAccountText->setVisible(false);
  342. ui->disconnectAccount->setVisible(false);
  343. }
  344. void AutoConfigStreamPage::ServiceChanged()
  345. {
  346. bool showMore = ui->service->currentData().toInt() == (int)ListOpt::ShowAll;
  347. if (showMore)
  348. return;
  349. std::string service = QT_TO_UTF8(ui->service->currentText());
  350. bool regionBased = service == "Twitch";
  351. bool testBandwidth = ui->doBandwidthTest->isChecked();
  352. bool custom = IsCustomService();
  353. bool ertmp_multitrack_video_available = service == "Twitch";
  354. bool custom_disclaimer = false;
  355. auto multitrack_video_name = QTStr("Basic.Settings.Stream.MultitrackVideoLabel");
  356. if (!custom) {
  357. OBSDataAutoRelease service_settings = obs_data_create();
  358. obs_data_set_string(service_settings, "service", service.c_str());
  359. OBSServiceAutoRelease obs_service =
  360. obs_service_create("rtmp_common", "temp service", service_settings, nullptr);
  361. if (obs_data_has_user_value(service_settings, "multitrack_video_name")) {
  362. multitrack_video_name = obs_data_get_string(service_settings, "multitrack_video_name");
  363. }
  364. if (obs_data_has_user_value(service_settings, "multitrack_video_disclaimer")) {
  365. ui->multitrackVideoInfo->setText(
  366. obs_data_get_string(service_settings, "multitrack_video_disclaimer"));
  367. custom_disclaimer = true;
  368. }
  369. }
  370. if (!custom_disclaimer) {
  371. ui->multitrackVideoInfo->setText(
  372. QTStr("MultitrackVideo.Info").arg(multitrack_video_name, service.c_str()));
  373. }
  374. ui->multitrackVideoInfo->setVisible(ertmp_multitrack_video_available);
  375. ui->useMultitrackVideo->setVisible(ertmp_multitrack_video_available);
  376. ui->useMultitrackVideo->setText(
  377. QTStr("Basic.AutoConfig.StreamPage.UseMultitrackVideo").arg(multitrack_video_name));
  378. ui->multitrackVideoInfo->setEnabled(wiz->hardwareEncodingAvailable);
  379. ui->useMultitrackVideo->setEnabled(wiz->hardwareEncodingAvailable);
  380. reset_service_ui_fields(service);
  381. /* Test three closest servers if "Auto" is available for Twitch */
  382. if ((service == "Twitch" && wiz->twitchAuto) || (service == "Amazon IVS" && wiz->amazonIVSAuto))
  383. regionBased = false;
  384. ui->streamkeyPageLayout->removeWidget(ui->serverLabel);
  385. ui->streamkeyPageLayout->removeWidget(ui->serverStackedWidget);
  386. if (custom) {
  387. ui->streamkeyPageLayout->insertRow(1, ui->serverLabel, ui->serverStackedWidget);
  388. ui->region->setVisible(false);
  389. ui->serverStackedWidget->setCurrentIndex(1);
  390. ui->serverStackedWidget->setVisible(true);
  391. ui->serverLabel->setVisible(true);
  392. } else {
  393. if (!testBandwidth)
  394. ui->streamkeyPageLayout->insertRow(2, ui->serverLabel, ui->serverStackedWidget);
  395. ui->region->setVisible(regionBased && testBandwidth);
  396. ui->serverStackedWidget->setCurrentIndex(0);
  397. ui->serverStackedWidget->setHidden(testBandwidth);
  398. ui->serverLabel->setHidden(testBandwidth);
  399. }
  400. wiz->testRegions = regionBased && testBandwidth;
  401. ui->bitrateLabel->setHidden(testBandwidth);
  402. ui->bitrate->setHidden(testBandwidth);
  403. OBSBasic *main = OBSBasic::Get();
  404. if (main->auth) {
  405. auto system_auth_service = main->auth->service();
  406. bool service_check = service.find(system_auth_service) != std::string::npos;
  407. #ifdef YOUTUBE_ENABLED
  408. service_check = service_check ? service_check
  409. : IsYouTubeService(system_auth_service) && IsYouTubeService(service);
  410. #endif
  411. if (service_check) {
  412. auth.reset();
  413. auth = main->auth;
  414. OnAuthConnected();
  415. }
  416. }
  417. UpdateCompleted();
  418. }
  419. void AutoConfigStreamPage::UpdateMoreInfoLink()
  420. {
  421. if (IsCustomService()) {
  422. ui->moreInfoButton->hide();
  423. return;
  424. }
  425. QString serviceName = ui->service->currentText();
  426. obs_properties_t *props = obs_get_service_properties("rtmp_common");
  427. obs_property_t *services = obs_properties_get(props, "service");
  428. OBSDataAutoRelease settings = obs_data_create();
  429. obs_data_set_string(settings, "service", QT_TO_UTF8(serviceName));
  430. obs_property_modified(services, settings);
  431. const char *more_info_link = obs_data_get_string(settings, "more_info_link");
  432. if (!more_info_link || (*more_info_link == '\0')) {
  433. ui->moreInfoButton->hide();
  434. } else {
  435. ui->moreInfoButton->setTargetUrl(QUrl(more_info_link));
  436. ui->moreInfoButton->show();
  437. }
  438. obs_properties_destroy(props);
  439. }
  440. void AutoConfigStreamPage::UpdateKeyLink()
  441. {
  442. QString serviceName = ui->service->currentText();
  443. QString customServer = ui->customServer->text().trimmed();
  444. QString streamKeyLink;
  445. obs_properties_t *props = obs_get_service_properties("rtmp_common");
  446. obs_property_t *services = obs_properties_get(props, "service");
  447. OBSDataAutoRelease settings = obs_data_create();
  448. obs_data_set_string(settings, "service", QT_TO_UTF8(serviceName));
  449. obs_property_modified(services, settings);
  450. streamKeyLink = obs_data_get_string(settings, "stream_key_link");
  451. if (customServer.contains("fbcdn.net") && IsCustomService()) {
  452. streamKeyLink = "https://www.facebook.com/live/producer?ref=OBS";
  453. }
  454. if (serviceName == "Dacast") {
  455. ui->streamKeyLabel->setText(QTStr("Basic.AutoConfig.StreamPage.EncoderKey"));
  456. ui->streamKeyLabel->setToolTip("");
  457. } else if (!IsCustomService()) {
  458. ui->streamKeyLabel->setText(QTStr("Basic.AutoConfig.StreamPage.StreamKey"));
  459. ui->streamKeyLabel->setToolTip("");
  460. } else {
  461. /* add tooltips for stream key */
  462. QString file = !App()->IsThemeDark() ? ":/res/images/help.svg" : ":/res/images/help_light.svg";
  463. QString lStr = "<html>%1 <img src='%2' style=' \
  464. vertical-align: bottom; \
  465. ' /></html>";
  466. ui->streamKeyLabel->setText(lStr.arg(QTStr("Basic.AutoConfig.StreamPage.StreamKey"), file));
  467. ui->streamKeyLabel->setToolTip(QTStr("Basic.AutoConfig.StreamPage.StreamKey.ToolTip"));
  468. }
  469. if (QString(streamKeyLink).isNull() || QString(streamKeyLink).isEmpty()) {
  470. ui->streamKeyButton->hide();
  471. } else {
  472. ui->streamKeyButton->setTargetUrl(QUrl(streamKeyLink));
  473. ui->streamKeyButton->show();
  474. }
  475. obs_properties_destroy(props);
  476. }
  477. void AutoConfigStreamPage::LoadServices(bool showAll)
  478. {
  479. obs_properties_t *props = obs_get_service_properties("rtmp_common");
  480. OBSDataAutoRelease settings = obs_data_create();
  481. obs_data_set_bool(settings, "show_all", showAll);
  482. obs_property_t *prop = obs_properties_get(props, "show_all");
  483. obs_property_modified(prop, settings);
  484. ui->service->blockSignals(true);
  485. ui->service->clear();
  486. QStringList names;
  487. obs_property_t *services = obs_properties_get(props, "service");
  488. size_t services_count = obs_property_list_item_count(services);
  489. for (size_t i = 0; i < services_count; i++) {
  490. const char *name = obs_property_list_item_string(services, i);
  491. names.push_back(name);
  492. }
  493. if (showAll)
  494. names.sort(Qt::CaseInsensitive);
  495. for (QString &name : names)
  496. ui->service->addItem(name);
  497. if (!showAll) {
  498. ui->service->addItem(QTStr("Basic.AutoConfig.StreamPage.Service.ShowAll"),
  499. QVariant((int)ListOpt::ShowAll));
  500. }
  501. ui->service->insertItem(0, QTStr("Basic.AutoConfig.StreamPage.Service.Custom"), QVariant((int)ListOpt::Custom));
  502. if (!lastService.isEmpty()) {
  503. int idx = ui->service->findText(lastService);
  504. if (idx != -1)
  505. ui->service->setCurrentIndex(idx);
  506. }
  507. obs_properties_destroy(props);
  508. ui->service->blockSignals(false);
  509. }
  510. void AutoConfigStreamPage::UpdateServerList()
  511. {
  512. QString serviceName = ui->service->currentText();
  513. bool showMore = ui->service->currentData().toInt() == (int)ListOpt::ShowAll;
  514. if (showMore) {
  515. LoadServices(true);
  516. ui->service->showPopup();
  517. return;
  518. } else {
  519. lastService = serviceName;
  520. }
  521. obs_properties_t *props = obs_get_service_properties("rtmp_common");
  522. obs_property_t *services = obs_properties_get(props, "service");
  523. OBSDataAutoRelease settings = obs_data_create();
  524. obs_data_set_string(settings, "service", QT_TO_UTF8(serviceName));
  525. obs_property_modified(services, settings);
  526. obs_property_t *servers = obs_properties_get(props, "server");
  527. ui->server->clear();
  528. size_t servers_count = obs_property_list_item_count(servers);
  529. for (size_t i = 0; i < servers_count; i++) {
  530. const char *name = obs_property_list_item_name(servers, i);
  531. const char *server = obs_property_list_item_string(servers, i);
  532. ui->server->addItem(name, server);
  533. }
  534. obs_properties_destroy(props);
  535. }
  536. void AutoConfigStreamPage::UpdateCompleted()
  537. {
  538. const bool custom = IsCustomService();
  539. if (ui->stackedWidget->currentIndex() == (int)Section::Connect ||
  540. (ui->key->text().isEmpty() && !auth && !custom)) {
  541. ready = false;
  542. } else {
  543. if (custom) {
  544. ready = !ui->customServer->text().isEmpty();
  545. } else {
  546. ready = !wiz->testRegions || ui->regionUS->isChecked() || ui->regionEU->isChecked() ||
  547. ui->regionAsia->isChecked() || ui->regionOther->isChecked();
  548. }
  549. }
  550. emit completeChanged();
  551. }