AutoConfigStreamPage.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699
  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. std::vector<OBSCanvasAutoRelease> canvases;
  142. canvases.emplace_back(obs_get_main_canvas());
  143. auto postData = constructGoLivePost(QString::fromStdString(wiz->key), std::nullopt,
  144. std::nullopt, false, canvases);
  145. OBSDataAutoRelease service_settings = obs_service_get_settings(service);
  146. auto multitrack_video_name = QTStr("Basic.Settings.Stream.MultitrackVideoLabel");
  147. if (obs_data_has_user_value(service_settings, "multitrack_video_name")) {
  148. multitrack_video_name = obs_data_get_string(service_settings, "multitrack_video_name");
  149. }
  150. try {
  151. auto config = DownloadGoLiveConfig(this, MultitrackVideoAutoConfigURL(service),
  152. postData, multitrack_video_name);
  153. for (const auto &endpoint : config.ingest_endpoints) {
  154. if (qstrnicmp("RTMP", endpoint.protocol.c_str(), 4) != 0)
  155. continue;
  156. std::string address = endpoint.url_template;
  157. auto pos = address.find("/{stream_key}");
  158. if (pos != address.npos)
  159. address.erase(pos);
  160. wiz->serviceConfigServers.push_back({address, address});
  161. }
  162. int multitrackVideoBitrate = 0;
  163. for (auto &encoder_config : config.encoder_configurations) {
  164. auto it = encoder_config.settings.find("bitrate");
  165. if (it == encoder_config.settings.end())
  166. continue;
  167. if (!it->is_number_integer())
  168. continue;
  169. int bitrate = 0;
  170. it->get_to(bitrate);
  171. multitrackVideoBitrate += bitrate;
  172. }
  173. if (multitrackVideoBitrate > 0) {
  174. wiz->startingBitrate = multitrackVideoBitrate;
  175. wiz->idealBitrate = multitrackVideoBitrate;
  176. wiz->multitrackVideo.targetBitrate = multitrackVideoBitrate;
  177. wiz->multitrackVideo.testSuccessful = true;
  178. }
  179. } catch (const MultitrackVideoError & /*err*/) {
  180. // FIXME: do something sensible
  181. }
  182. }
  183. }
  184. if (wiz->service != AutoConfig::Service::Twitch && wiz->service != AutoConfig::Service::YouTube &&
  185. wiz->service != AutoConfig::Service::AmazonIVS && wiz->bandwidthTest) {
  186. QMessageBox::StandardButton button;
  187. #define WARNING_TEXT(x) QTStr("Basic.AutoConfig.StreamPage.StreamWarning." x)
  188. button = OBSMessageBox::question(this, WARNING_TEXT("Title"), WARNING_TEXT("Text"));
  189. #undef WARNING_TEXT
  190. if (button == QMessageBox::No)
  191. return false;
  192. }
  193. return true;
  194. }
  195. void AutoConfigStreamPage::on_show_clicked()
  196. {
  197. if (ui->key->echoMode() == QLineEdit::Password) {
  198. ui->key->setEchoMode(QLineEdit::Normal);
  199. ui->show->setText(QTStr("Hide"));
  200. } else {
  201. ui->key->setEchoMode(QLineEdit::Password);
  202. ui->show->setText(QTStr("Show"));
  203. }
  204. }
  205. void AutoConfigStreamPage::OnOAuthStreamKeyConnected()
  206. {
  207. OAuthStreamKey *a = reinterpret_cast<OAuthStreamKey *>(auth.get());
  208. if (a) {
  209. bool validKey = !a->key().empty();
  210. if (validKey)
  211. ui->key->setText(QT_UTF8(a->key().c_str()));
  212. ui->streamKeyWidget->setVisible(false);
  213. ui->streamKeyLabel->setVisible(false);
  214. ui->connectAccount2->setVisible(false);
  215. ui->disconnectAccount->setVisible(true);
  216. ui->useStreamKeyAdv->setVisible(false);
  217. ui->connectedAccountLabel->setVisible(false);
  218. ui->connectedAccountText->setVisible(false);
  219. #ifdef YOUTUBE_ENABLED
  220. if (IsYouTubeService(a->service())) {
  221. ui->key->clear();
  222. ui->connectedAccountLabel->setVisible(true);
  223. ui->connectedAccountText->setVisible(true);
  224. ui->connectedAccountText->setText(QTStr("Auth.LoadingChannel.Title"));
  225. YoutubeApiWrappers *ytAuth = reinterpret_cast<YoutubeApiWrappers *>(a);
  226. ChannelDescription cd;
  227. if (ytAuth->GetChannelDescription(cd)) {
  228. ui->connectedAccountText->setText(cd.title);
  229. /* Create throwaway stream key for bandwidth test */
  230. if (ui->doBandwidthTest->isChecked()) {
  231. StreamDescription stream = {"", "", "OBS Studio Test Stream"};
  232. if (ytAuth->InsertStream(stream)) {
  233. ui->key->setText(stream.name);
  234. }
  235. }
  236. }
  237. }
  238. #endif
  239. }
  240. ui->stackedWidget->setCurrentIndex((int)Section::StreamKey);
  241. UpdateCompleted();
  242. }
  243. void AutoConfigStreamPage::OnAuthConnected()
  244. {
  245. std::string service = QT_TO_UTF8(ui->service->currentText());
  246. Auth::Type type = Auth::AuthType(service);
  247. if (type == Auth::Type::OAuth_StreamKey || type == Auth::Type::OAuth_LinkedAccount) {
  248. OnOAuthStreamKeyConnected();
  249. }
  250. }
  251. void AutoConfigStreamPage::on_connectAccount_clicked()
  252. {
  253. std::string service = QT_TO_UTF8(ui->service->currentText());
  254. OAuth::DeleteCookies(service);
  255. auth = OAuthStreamKey::Login(this, service);
  256. if (!!auth) {
  257. OnAuthConnected();
  258. ui->useStreamKeyAdv->setVisible(false);
  259. }
  260. }
  261. #define DISCONNECT_COMFIRM_TITLE "Basic.AutoConfig.StreamPage.DisconnectAccount.Confirm.Title"
  262. #define DISCONNECT_COMFIRM_TEXT "Basic.AutoConfig.StreamPage.DisconnectAccount.Confirm.Text"
  263. void AutoConfigStreamPage::on_disconnectAccount_clicked()
  264. {
  265. QMessageBox::StandardButton button;
  266. button = OBSMessageBox::question(this, QTStr(DISCONNECT_COMFIRM_TITLE), QTStr(DISCONNECT_COMFIRM_TEXT));
  267. if (button == QMessageBox::No) {
  268. return;
  269. }
  270. OBSBasic *main = OBSBasic::Get();
  271. main->auth.reset();
  272. auth.reset();
  273. std::string service = QT_TO_UTF8(ui->service->currentText());
  274. #ifdef BROWSER_AVAILABLE
  275. OAuth::DeleteCookies(service);
  276. #endif
  277. reset_service_ui_fields(service);
  278. ui->streamKeyWidget->setVisible(true);
  279. ui->streamKeyLabel->setVisible(true);
  280. ui->key->setText("");
  281. ui->connectedAccountLabel->setVisible(false);
  282. ui->connectedAccountText->setVisible(false);
  283. /* Restore key link when disconnecting account */
  284. UpdateKeyLink();
  285. }
  286. void AutoConfigStreamPage::on_useStreamKey_clicked()
  287. {
  288. ui->stackedWidget->setCurrentIndex((int)Section::StreamKey);
  289. UpdateCompleted();
  290. }
  291. void AutoConfigStreamPage::on_preferHardware_clicked()
  292. {
  293. auto *main = OBSBasic::Get();
  294. bool multitrackVideoEnabled = config_has_user_value(main->Config(), "Stream1", "EnableMultitrackVideo")
  295. ? config_get_bool(main->Config(), "Stream1", "EnableMultitrackVideo")
  296. : true;
  297. ui->useMultitrackVideo->setEnabled(ui->preferHardware->isChecked());
  298. ui->multitrackVideoInfo->setEnabled(ui->preferHardware->isChecked());
  299. ui->useMultitrackVideo->setChecked(ui->preferHardware->isChecked() && multitrackVideoEnabled);
  300. }
  301. static inline bool is_auth_service(const std::string &service)
  302. {
  303. return Auth::AuthType(service) != Auth::Type::None;
  304. }
  305. static inline bool is_external_oauth(const std::string &service)
  306. {
  307. return Auth::External(service);
  308. }
  309. void AutoConfigStreamPage::reset_service_ui_fields(std::string &service)
  310. {
  311. #ifdef YOUTUBE_ENABLED
  312. // when account is already connected:
  313. OAuthStreamKey *a = reinterpret_cast<OAuthStreamKey *>(auth.get());
  314. if (a && service == a->service() && IsYouTubeService(a->service())) {
  315. ui->connectedAccountLabel->setVisible(true);
  316. ui->connectedAccountText->setVisible(true);
  317. ui->connectAccount2->setVisible(false);
  318. ui->disconnectAccount->setVisible(true);
  319. return;
  320. }
  321. #endif
  322. bool external_oauth = is_external_oauth(service);
  323. if (external_oauth) {
  324. ui->streamKeyWidget->setVisible(false);
  325. ui->streamKeyLabel->setVisible(false);
  326. ui->connectAccount2->setVisible(true);
  327. ui->useStreamKeyAdv->setVisible(true);
  328. ui->stackedWidget->setCurrentIndex((int)Section::StreamKey);
  329. } else if (cef) {
  330. QString key = ui->key->text();
  331. bool can_auth = is_auth_service(service);
  332. int page = can_auth && key.isEmpty() ? (int)Section::Connect : (int)Section::StreamKey;
  333. ui->stackedWidget->setCurrentIndex(page);
  334. ui->streamKeyWidget->setVisible(true);
  335. ui->streamKeyLabel->setVisible(true);
  336. ui->connectAccount2->setVisible(can_auth);
  337. ui->useStreamKeyAdv->setVisible(false);
  338. } else {
  339. ui->connectAccount2->setVisible(false);
  340. ui->useStreamKeyAdv->setVisible(false);
  341. }
  342. ui->connectedAccountLabel->setVisible(false);
  343. ui->connectedAccountText->setVisible(false);
  344. ui->disconnectAccount->setVisible(false);
  345. }
  346. void AutoConfigStreamPage::ServiceChanged()
  347. {
  348. bool showMore = ui->service->currentData().toInt() == (int)ListOpt::ShowAll;
  349. if (showMore)
  350. return;
  351. std::string service = QT_TO_UTF8(ui->service->currentText());
  352. bool regionBased = service == "Twitch";
  353. bool testBandwidth = ui->doBandwidthTest->isChecked();
  354. bool custom = IsCustomService();
  355. bool ertmp_multitrack_video_available = service == "Twitch";
  356. bool custom_disclaimer = false;
  357. auto multitrack_video_name = QTStr("Basic.Settings.Stream.MultitrackVideoLabel");
  358. if (!custom) {
  359. OBSDataAutoRelease service_settings = obs_data_create();
  360. obs_data_set_string(service_settings, "service", service.c_str());
  361. OBSServiceAutoRelease obs_service =
  362. obs_service_create("rtmp_common", "temp service", service_settings, nullptr);
  363. if (obs_data_has_user_value(service_settings, "multitrack_video_name")) {
  364. multitrack_video_name = obs_data_get_string(service_settings, "multitrack_video_name");
  365. }
  366. if (obs_data_has_user_value(service_settings, "multitrack_video_disclaimer")) {
  367. ui->multitrackVideoInfo->setText(
  368. obs_data_get_string(service_settings, "multitrack_video_disclaimer"));
  369. custom_disclaimer = true;
  370. }
  371. }
  372. if (!custom_disclaimer) {
  373. ui->multitrackVideoInfo->setText(
  374. QTStr("MultitrackVideo.Info").arg(multitrack_video_name, service.c_str()));
  375. }
  376. ui->multitrackVideoInfo->setVisible(ertmp_multitrack_video_available);
  377. ui->useMultitrackVideo->setVisible(ertmp_multitrack_video_available);
  378. ui->useMultitrackVideo->setText(
  379. QTStr("Basic.AutoConfig.StreamPage.UseMultitrackVideo").arg(multitrack_video_name));
  380. ui->multitrackVideoInfo->setEnabled(wiz->hardwareEncodingAvailable);
  381. ui->useMultitrackVideo->setEnabled(wiz->hardwareEncodingAvailable);
  382. reset_service_ui_fields(service);
  383. /* Test three closest servers if "Auto" is available for Twitch */
  384. if ((service == "Twitch" && wiz->twitchAuto) || (service == "Amazon IVS" && wiz->amazonIVSAuto))
  385. regionBased = false;
  386. ui->streamkeyPageLayout->removeWidget(ui->serverLabel);
  387. ui->streamkeyPageLayout->removeWidget(ui->serverStackedWidget);
  388. if (custom) {
  389. ui->streamkeyPageLayout->insertRow(1, ui->serverLabel, ui->serverStackedWidget);
  390. ui->region->setVisible(false);
  391. ui->serverStackedWidget->setCurrentIndex(1);
  392. ui->serverStackedWidget->setVisible(true);
  393. ui->serverLabel->setVisible(true);
  394. } else {
  395. if (!testBandwidth)
  396. ui->streamkeyPageLayout->insertRow(2, ui->serverLabel, ui->serverStackedWidget);
  397. ui->region->setVisible(regionBased && testBandwidth);
  398. ui->serverStackedWidget->setCurrentIndex(0);
  399. ui->serverStackedWidget->setHidden(testBandwidth);
  400. ui->serverLabel->setHidden(testBandwidth);
  401. }
  402. wiz->testRegions = regionBased && testBandwidth;
  403. ui->bitrateLabel->setHidden(testBandwidth);
  404. ui->bitrate->setHidden(testBandwidth);
  405. OBSBasic *main = OBSBasic::Get();
  406. if (main->auth) {
  407. auto system_auth_service = main->auth->service();
  408. bool service_check = service.find(system_auth_service) != std::string::npos;
  409. #ifdef YOUTUBE_ENABLED
  410. service_check = service_check ? service_check
  411. : IsYouTubeService(system_auth_service) && IsYouTubeService(service);
  412. #endif
  413. if (service_check) {
  414. auth.reset();
  415. auth = main->auth;
  416. OnAuthConnected();
  417. }
  418. }
  419. UpdateCompleted();
  420. }
  421. void AutoConfigStreamPage::UpdateMoreInfoLink()
  422. {
  423. if (IsCustomService()) {
  424. ui->moreInfoButton->hide();
  425. return;
  426. }
  427. QString serviceName = ui->service->currentText();
  428. obs_properties_t *props = obs_get_service_properties("rtmp_common");
  429. obs_property_t *services = obs_properties_get(props, "service");
  430. OBSDataAutoRelease settings = obs_data_create();
  431. obs_data_set_string(settings, "service", QT_TO_UTF8(serviceName));
  432. obs_property_modified(services, settings);
  433. const char *more_info_link = obs_data_get_string(settings, "more_info_link");
  434. if (!more_info_link || (*more_info_link == '\0')) {
  435. ui->moreInfoButton->hide();
  436. } else {
  437. ui->moreInfoButton->setTargetUrl(QUrl(more_info_link));
  438. ui->moreInfoButton->show();
  439. }
  440. obs_properties_destroy(props);
  441. }
  442. void AutoConfigStreamPage::UpdateKeyLink()
  443. {
  444. QString serviceName = ui->service->currentText();
  445. QString customServer = ui->customServer->text().trimmed();
  446. QString streamKeyLink;
  447. obs_properties_t *props = obs_get_service_properties("rtmp_common");
  448. obs_property_t *services = obs_properties_get(props, "service");
  449. OBSDataAutoRelease settings = obs_data_create();
  450. obs_data_set_string(settings, "service", QT_TO_UTF8(serviceName));
  451. obs_property_modified(services, settings);
  452. streamKeyLink = obs_data_get_string(settings, "stream_key_link");
  453. if (customServer.contains("fbcdn.net") && IsCustomService()) {
  454. streamKeyLink = "https://www.facebook.com/live/producer?ref=OBS";
  455. }
  456. if (serviceName == "Dacast") {
  457. ui->streamKeyLabel->setText(QTStr("Basic.AutoConfig.StreamPage.EncoderKey"));
  458. ui->streamKeyLabel->setToolTip("");
  459. } else if (!IsCustomService()) {
  460. ui->streamKeyLabel->setText(QTStr("Basic.AutoConfig.StreamPage.StreamKey"));
  461. ui->streamKeyLabel->setToolTip("");
  462. } else {
  463. /* add tooltips for stream key */
  464. QString file = !App()->IsThemeDark() ? ":/res/images/help.svg" : ":/res/images/help_light.svg";
  465. QString lStr = "<html>%1 <img src='%2' style=' \
  466. vertical-align: bottom; \
  467. ' /></html>";
  468. ui->streamKeyLabel->setText(lStr.arg(QTStr("Basic.AutoConfig.StreamPage.StreamKey"), file));
  469. ui->streamKeyLabel->setToolTip(QTStr("Basic.AutoConfig.StreamPage.StreamKey.ToolTip"));
  470. }
  471. if (QString(streamKeyLink).isNull() || QString(streamKeyLink).isEmpty()) {
  472. ui->streamKeyButton->hide();
  473. } else {
  474. ui->streamKeyButton->setTargetUrl(QUrl(streamKeyLink));
  475. ui->streamKeyButton->show();
  476. }
  477. obs_properties_destroy(props);
  478. }
  479. void AutoConfigStreamPage::LoadServices(bool showAll)
  480. {
  481. obs_properties_t *props = obs_get_service_properties("rtmp_common");
  482. OBSDataAutoRelease settings = obs_data_create();
  483. obs_data_set_bool(settings, "show_all", showAll);
  484. obs_property_t *prop = obs_properties_get(props, "show_all");
  485. obs_property_modified(prop, settings);
  486. ui->service->blockSignals(true);
  487. ui->service->clear();
  488. QStringList names;
  489. obs_property_t *services = obs_properties_get(props, "service");
  490. size_t services_count = obs_property_list_item_count(services);
  491. for (size_t i = 0; i < services_count; i++) {
  492. const char *name = obs_property_list_item_string(services, i);
  493. names.push_back(name);
  494. }
  495. if (showAll)
  496. names.sort(Qt::CaseInsensitive);
  497. for (QString &name : names)
  498. ui->service->addItem(name);
  499. if (!showAll) {
  500. ui->service->addItem(QTStr("Basic.AutoConfig.StreamPage.Service.ShowAll"),
  501. QVariant((int)ListOpt::ShowAll));
  502. }
  503. ui->service->insertItem(0, QTStr("Basic.AutoConfig.StreamPage.Service.Custom"), QVariant((int)ListOpt::Custom));
  504. if (!lastService.isEmpty()) {
  505. int idx = ui->service->findText(lastService);
  506. if (idx != -1)
  507. ui->service->setCurrentIndex(idx);
  508. }
  509. obs_properties_destroy(props);
  510. ui->service->blockSignals(false);
  511. }
  512. void AutoConfigStreamPage::UpdateServerList()
  513. {
  514. QString serviceName = ui->service->currentText();
  515. bool showMore = ui->service->currentData().toInt() == (int)ListOpt::ShowAll;
  516. if (showMore) {
  517. LoadServices(true);
  518. ui->service->showPopup();
  519. return;
  520. } else {
  521. lastService = serviceName;
  522. }
  523. obs_properties_t *props = obs_get_service_properties("rtmp_common");
  524. obs_property_t *services = obs_properties_get(props, "service");
  525. OBSDataAutoRelease settings = obs_data_create();
  526. obs_data_set_string(settings, "service", QT_TO_UTF8(serviceName));
  527. obs_property_modified(services, settings);
  528. obs_property_t *servers = obs_properties_get(props, "server");
  529. ui->server->clear();
  530. size_t servers_count = obs_property_list_item_count(servers);
  531. for (size_t i = 0; i < servers_count; i++) {
  532. const char *name = obs_property_list_item_name(servers, i);
  533. const char *server = obs_property_list_item_string(servers, i);
  534. ui->server->addItem(name, server);
  535. }
  536. obs_properties_destroy(props);
  537. }
  538. void AutoConfigStreamPage::UpdateCompleted()
  539. {
  540. const bool custom = IsCustomService();
  541. if (ui->stackedWidget->currentIndex() == (int)Section::Connect ||
  542. (ui->key->text().isEmpty() && !auth && !custom)) {
  543. ready = false;
  544. } else {
  545. if (custom) {
  546. ready = !ui->customServer->text().isEmpty();
  547. } else {
  548. ready = !wiz->testRegions || ui->regionUS->isChecked() || ui->regionEU->isChecked() ||
  549. ui->regionAsia->isChecked() || ui->regionOther->isChecked();
  550. }
  551. }
  552. emit completeChanged();
  553. }