From 43adf528d2368be6242f1127592eafa80675693e Mon Sep 17 00:00:00 2001 From: Johann Garces Date: Mon, 28 Sep 2020 21:29:48 -0700 Subject: [PATCH] UI: PreStream Wizard add completion page Adds a completion page with content that depends on destinations. Back button is disabled on the last page where application will take place since updating settings is undoable. Various code fixes. --- UI/CMakeLists.txt | 2 + UI/common-settings.cpp | 10 +-- UI/data/locale/en-US.ini | 4 +- .../encoder-settings-provider-facebook.cpp | 21 +++++- .../encoder-settings-provider-facebook.hpp | 1 - UI/pre-stream-wizard/page-completed.cpp | 69 +++++++++++++++++++ UI/pre-stream-wizard/page-completed.hpp | 26 +++++++ UI/pre-stream-wizard/page-select-settings.cpp | 13 ++-- UI/pre-stream-wizard/page-select-settings.hpp | 1 - UI/pre-stream-wizard/page-start-prompt.cpp | 6 -- UI/pre-stream-wizard/page-start-prompt.hpp | 1 - .../pre-stream-current-settings.hpp | 30 ++++---- UI/pre-stream-wizard/pre-stream-wizard.cpp | 15 +++- .../setting-selection-row.cpp | 4 -- .../setting-selection-row.hpp | 1 - UI/streaming-settings-util.cpp | 2 +- 16 files changed, 160 insertions(+), 46 deletions(-) create mode 100644 UI/pre-stream-wizard/page-completed.cpp create mode 100644 UI/pre-stream-wizard/page-completed.hpp diff --git a/UI/CMakeLists.txt b/UI/CMakeLists.txt index d9fdebdb555b83..86e7dc0a78abaf 100644 --- a/UI/CMakeLists.txt +++ b/UI/CMakeLists.txt @@ -195,6 +195,7 @@ set(obs_SOURCES pre-stream-wizard/page-input-display.cpp pre-stream-wizard/page-start-prompt.cpp pre-stream-wizard/page-select-settings.cpp + pre-stream-wizard/page-completed.cpp pre-stream-wizard/setting-selection-row.cpp pre-stream-wizard/encoder-settings-provider-facebook.cpp obs-app.cpp @@ -274,6 +275,7 @@ set(obs_HEADERS pre-stream-wizard/page-input-display.hpp pre-stream-wizard/page-start-prompt.hpp pre-stream-wizard/page-select-settings.hpp + pre-stream-wizard/page-completed.hpp pre-stream-wizard/setting-selection-row.hpp pre-stream-wizard/encoder-settings-provider-facebook.hpp obs-app.hpp diff --git a/UI/common-settings.cpp b/UI/common-settings.cpp index 2c5d641443d95a..ecfd1dc07845cd 100644 --- a/UI/common-settings.cpp +++ b/UI/common-settings.cpp @@ -2,7 +2,7 @@ #include "audio-encoders.hpp" -bool IsAdvancedMode(config_t *config) +static bool IsAdvancedMode(config_t *config) { const char *outputMode = config_get_string(config, "Output", "Mode"); return (strcmp(outputMode, "Advanced") == 0); @@ -16,7 +16,7 @@ OBSData CommonSettings::GetDataFromJsonFile(const char *jsonFile) int ret = GetProfilePath(fullPath, sizeof(fullPath), jsonFile); if (ret > 0) { BPtr jsonData = os_quick_read_utf8_file(fullPath); - if (!!jsonData) { + if (jsonData) { data = obs_data_create_from_json(jsonData); } } @@ -145,7 +145,7 @@ int CommonSettings::GetStreamingAudioBitrate(config_t *config) int CommonSettings::GetSimpleAudioBitrate(config_t *config) { - int bitrate = (int)config_get_uint(config, "SimpleOutput", "ABitrate"); + int bitrate = config_get_uint(config, "SimpleOutput", "ABitrate"); return FindClosestAvailableAACBitrate(bitrate); } @@ -163,9 +163,11 @@ int CommonSettings::GetAdvancedAudioBitrateForTrack(config_t *config, "Track4Bitrate", "Track5Bitrate", "Track6Bitrate", }; - // Sanity check for out of bounds + // Sanity check for out of bounds, clamp to bounds if (trackIndex > 5) trackIndex = 5; + if (trackIndex < 0) + trackIndex = 0; int bitrate = (int)config_get_uint(config, "AdvOut", names[trackIndex]); return FindClosestAvailableAACBitrate(bitrate); diff --git a/UI/data/locale/en-US.ini b/UI/data/locale/en-US.ini index 34b24a136d513f..36119f0d923530 100644 --- a/UI/data/locale/en-US.ini +++ b/UI/data/locale/en-US.ini @@ -727,7 +727,9 @@ PreLiveWizard.Configure.Error.JsonParse="Problem with server response" PreLiveWizard.Configure.Error.JsonParse.Description="Wizard is unavailble at the moment." PreLiveWizard.Selection.Title="Settings Suggested" PreLiveWizard.Selection.Description="Suggested video settings for your best stream." - +PreLiveWizard.Completed.Title="Encoder configured" +PreLiveWizard.Completed.BodyText="Applied suggested settings and encoder is setup to stream. You can now close the wizard." +PreLiveWizard.Completed.FacebookOnly="To finish going live go to Facebook Live:" # basic mode 'output' settings Basic.Settings.Output="Output" diff --git a/UI/pre-stream-wizard/encoder-settings-provider-facebook.cpp b/UI/pre-stream-wizard/encoder-settings-provider-facebook.cpp index 7d4d27a370e50c..22768d7a81b0de 100644 --- a/UI/pre-stream-wizard/encoder-settings-provider-facebook.cpp +++ b/UI/pre-stream-wizard/encoder-settings-provider-facebook.cpp @@ -12,7 +12,6 @@ #include #include #include -#include #include "obs-app.hpp" #include "obs-config.h" @@ -57,7 +56,7 @@ void FacebookEncoderSettingsProvider::makeRequest(QUrl &url) "application/json"); // GET is made async - settingsReply_ = restclient_->get(request); + restclient_->get(request); // This is the callback when data is ready connect(restclient_, &QNetworkAccessManager::finished, this, &FacebookEncoderSettingsProvider::handleResponse); @@ -66,7 +65,7 @@ void FacebookEncoderSettingsProvider::makeRequest(QUrl &url) QUrlQuery FacebookEncoderSettingsProvider::inputVideoQueryFromCurrentSettings() { // Get input settings, shorten name - EncoderSettingsRequest *input = currentSettings_.get(); + EncoderSettingsRequest *input = currentSettings_.data(); QUrlQuery inputVideoSettingsQuery; inputVideoSettingsQuery.addQueryItem("video_type", "live"); @@ -126,6 +125,10 @@ void addInt(const QJsonObject &json, const char *jsonKey, SettingsMap *map, if (json[jsonKey].isDouble()) { map->insert(mapKey, QPair(QVariant(json[jsonKey].toInt()), true)); + } else { + blog(LOG_WARNING, + "FacebookEncoderSettingsProvider could not parse %s to Int", + jsonKey); } } @@ -140,6 +143,10 @@ void addStringDouble(const QJsonObject &json, const char *jsonKey, double numberValue = valueString.toDouble(&converted); if (converted) { map->insert(mapKey, QPair(QVariant(numberValue), true)); + } else { + blog(LOG_WARNING, + "FacebookEncoderSettingsProvider couldn't parse %s to Double from String", + jsonKey); } } @@ -149,6 +156,10 @@ void addQString(const QJsonObject &json, const char *jsonKey, SettingsMap *map, if (json[jsonKey].isString()) { map->insert(mapKey, QPair(QVariant(json[jsonKey].toString()), true)); + } else { + blog(LOG_WARNING, + "FacebookEncoderSettingsProvider could not parse %s to Strng", + jsonKey); } } @@ -158,6 +169,10 @@ void addBool(const QJsonObject &json, const char *jsonKey, SettingsMap *map, if (json[jsonKey].isBool()) { map->insert(mapKey, QPair(QVariant(json[jsonKey].toBool()), true)); + } else { + blog(LOG_WARNING, + "FacebookEncoderSettingsProvider could not parse %s to Bool", + jsonKey); } } diff --git a/UI/pre-stream-wizard/encoder-settings-provider-facebook.hpp b/UI/pre-stream-wizard/encoder-settings-provider-facebook.hpp index 6de922d2025086..112b4d6d25714b 100644 --- a/UI/pre-stream-wizard/encoder-settings-provider-facebook.hpp +++ b/UI/pre-stream-wizard/encoder-settings-provider-facebook.hpp @@ -37,7 +37,6 @@ class FacebookEncoderSettingsProvider : public QObject { private: QSharedPointer currentSettings_; QNetworkAccessManager *restclient_; - QNetworkReply *settingsReply_; void makeRequest(QUrl &url); QUrlQuery inputVideoQueryFromCurrentSettings(); diff --git a/UI/pre-stream-wizard/page-completed.cpp b/UI/pre-stream-wizard/page-completed.cpp new file mode 100644 index 00000000000000..3def54f158d5b0 --- /dev/null +++ b/UI/pre-stream-wizard/page-completed.cpp @@ -0,0 +1,69 @@ +#include "page-completed.hpp" + +#include +#include +#include +#include +#include +#include + +#include "obs-app.hpp" + +namespace StreamWizard { + +CompletedPage::CompletedPage(Destination destination, + LaunchContext launchContext, QWidget *parent) + : QWizardPage(parent) +{ + destination_ = destination; + launchContext_ = launchContext; + + setTitle(QTStr("PreLiveWizard.Completed.Title")); + + QVBoxLayout *mainlayout = new QVBoxLayout(this); + setLayout(mainlayout); + + // Later will suggest starting stream if launchContext is PreStream + QLabel *closeLabel = + new QLabel(QTStr("PreLiveWizard.Completed.BodyText"), this); + closeLabel->setWordWrap(true); + mainlayout->addWidget(closeLabel); + + if (destination_ == Destination::Facebook) { + mainlayout->addSpacerItem(new QSpacerItem(12, 12)); + + QLabel *facebookGoLiveLabel = new QLabel( + QTStr("PreLiveWizard.Completed.FacebookOnly"), this); + facebookGoLiveLabel->setWordWrap(true); + QPushButton *launchButton = new QPushButton( + QTStr("PreLiveWizard.Prompt.FBResolutionHelpButton.FB"), + this); + launchButton->setToolTip(QTStr( + "PreLiveWizard.Prompt.FBResolutionHelpButton.FB.ToolTip")); + connect(launchButton, &QPushButton::clicked, this, + &CompletedPage::didPushOpenWebsite); + + mainlayout->addWidget(facebookGoLiveLabel); + mainlayout->addWidget(launchButton); + } +} + +void CompletedPage::didPushOpenWebsite() +{ + QUrl helpUrl; + + // Prepare per-destination + if (destination_ == Destination::Facebook) { + helpUrl = QUrl( + "https://www.facebook.com/live/producer/?ref=OBS_Wizard", + QUrl::TolerantMode); + } else { + return; + } + // Launch + if (helpUrl.isValid()) { + QDesktopServices::openUrl(helpUrl); + } +} + +} // namespace StreamWizard diff --git a/UI/pre-stream-wizard/page-completed.hpp b/UI/pre-stream-wizard/page-completed.hpp new file mode 100644 index 00000000000000..b634ad19f6a966 --- /dev/null +++ b/UI/pre-stream-wizard/page-completed.hpp @@ -0,0 +1,26 @@ +#pragma once + +#include + +#include "pre-stream-current-settings.hpp" + +namespace StreamWizard { + +// Last Page +class CompletedPage : public QWizardPage { + Q_OBJECT + +public: + CompletedPage(Destination destination, LaunchContext launchContext, + QWidget *parent = nullptr); + +private: + Destination destination_; + LaunchContext launchContext_; + +private slots: + void didPushOpenWebsite(); + +}; // class CompletedPage + +} // namespace StreamWizard diff --git a/UI/pre-stream-wizard/page-select-settings.cpp b/UI/pre-stream-wizard/page-select-settings.cpp index ae807d46edcbd1..383b1c5a72b8ca 100644 --- a/UI/pre-stream-wizard/page-select-settings.cpp +++ b/UI/pre-stream-wizard/page-select-settings.cpp @@ -16,11 +16,12 @@ SelectionPage::SelectionPage(QWidget *parent) : QWizardPage(parent) { this->setTitle(QTStr("PreLiveWizard.Selection.Title")); setupLayout(); -} -SelectionPage::~SelectionPage() -{ - // nop + setButtonText(QWizard::WizardButton::NextButton, + QTStr("Basic.AutoConfig.ApplySettings")); + setButtonText(QWizard::WizardButton::CommitButton, + QTStr("Basic.AutoConfig.ApplySettings")); + setCommitPage(true); } void SelectionPage::setupLayout() @@ -58,7 +59,7 @@ void SelectionPage::setSettingsMap(QSharedPointer settingsMap) return; } settingsMap_ = settingsMap; - SettingsMap *mapInfo = settingsMap_.get(); + SettingsMap *mapInfo = settingsMap_.data(); if (mapInfo->contains(SettingsResponseKeys.videoBitrate)) { QVariant data = @@ -190,7 +191,7 @@ void SelectionPage::checkboxRowChanged(const char *propertyKey, bool selected) return; } - SettingsMap *mapInfo = settingsMap_.get(); + SettingsMap *mapInfo = settingsMap_.data(); if (mapInfo == nullptr || !mapInfo->contains(propertyKey)) { return; diff --git a/UI/pre-stream-wizard/page-select-settings.hpp b/UI/pre-stream-wizard/page-select-settings.hpp index 80ade3cf2474e8..6ef4e6c495c184 100644 --- a/UI/pre-stream-wizard/page-select-settings.hpp +++ b/UI/pre-stream-wizard/page-select-settings.hpp @@ -22,7 +22,6 @@ class SelectionPage : public QWizardPage { public: SelectionPage(QWidget *parent = nullptr); - ~SelectionPage(); // Sets data to layout scrollbox void setSettingsMap(QSharedPointer settingsMap); diff --git a/UI/pre-stream-wizard/page-start-prompt.cpp b/UI/pre-stream-wizard/page-start-prompt.cpp index 8c847eeac9b120..ef3fa8e9a2dc0b 100644 --- a/UI/pre-stream-wizard/page-start-prompt.cpp +++ b/UI/pre-stream-wizard/page-start-prompt.cpp @@ -39,12 +39,6 @@ StartPage::StartPage(Destination dest, LaunchContext launchContext, resCurrentButton_->setChecked(true); } } - -StartPage::~StartPage() -{ - // nop -} - void StartPage::createLayout() { QVBoxLayout *mainlayout = new QVBoxLayout(this); diff --git a/UI/pre-stream-wizard/page-start-prompt.hpp b/UI/pre-stream-wizard/page-start-prompt.hpp index 85475f41bf5b40..418c30b6084fe9 100644 --- a/UI/pre-stream-wizard/page-start-prompt.hpp +++ b/UI/pre-stream-wizard/page-start-prompt.hpp @@ -16,7 +16,6 @@ class StartPage : public QWizardPage { public: StartPage(Destination dest, LaunchContext launchContext, QSize videoSize, QWidget *parent = nullptr); - ~StartPage(); signals: // emitted selected resolution from start page radio buttons diff --git a/UI/pre-stream-wizard/pre-stream-current-settings.hpp b/UI/pre-stream-wizard/pre-stream-current-settings.hpp index cc52ad09296fd1..a05ffaf8bfacc5 100644 --- a/UI/pre-stream-wizard/pre-stream-current-settings.hpp +++ b/UI/pre-stream-wizard/pre-stream-current-settings.hpp @@ -97,20 +97,20 @@ static const struct { const char *streamRateControlMode; // string "CBR" const char *streamBufferSize; // int (5000 kb) } SettingsResponseKeys = { - .videoWidth = "videoWidth", - .videoHeight = "videoHeight", - .framerate = "framerate", - .videoBitrate = "videoBitrate", - .protocol = "protocol", - .videoCodec = "videoCodec", - .h264Profile = "h264Profile", - .h264Level = "h264Level", - .gopSizeInFrames = "gopSizeInFrames", - .gopType = "gopType", - .gopClosed = "gopClosed", - .gopBFrames = "gopBFrames", - .gopRefFrames = "gopRefFrames", - .streamRateControlMode = "streamRateControlMode", - .streamBufferSize = "streamBufferSize", + "videoWidth", + "videoHeight", + "framerate", + "videoBitrate", + "protocol", + "videoCodec", + "h264Profile", + "h264Level", + "gopSizeInFrames", + "gopType", + "gopClosed", + "gopBFrames", + "gopRefFrames", + "streamRateControlMode", + "streamBufferSize", }; } diff --git a/UI/pre-stream-wizard/pre-stream-wizard.cpp b/UI/pre-stream-wizard/pre-stream-wizard.cpp index fb9ec0a511a198..d1edc1398af56c 100644 --- a/UI/pre-stream-wizard/pre-stream-wizard.cpp +++ b/UI/pre-stream-wizard/pre-stream-wizard.cpp @@ -11,10 +11,16 @@ #include "page-input-display.hpp" #include "page-start-prompt.hpp" #include "page-select-settings.hpp" +#include "page-completed.hpp" namespace StreamWizard { -enum PSW_Page { Page_StartPrompt, Page_Loading, Page_Selections }; +enum PSW_Page { + Page_StartPrompt, + Page_Loading, + Page_Selections, + Page_Complete, +}; PreStreamWizard::PreStreamWizard( Destination dest, LaunchContext launchContext, @@ -45,6 +51,11 @@ PreStreamWizard::PreStreamWizard( // Suggestion Selection Page selectionPage_ = new SelectionPage(); setPage(Page_Selections, selectionPage_); + + // Ending + Confirmation Page + CompletedPage *completedPage = + new CompletedPage(destination_, launchContext_, this); + setPage(Page_Complete, completedPage); } void PreStreamWizard::requestSettings() @@ -106,7 +117,7 @@ void PreStreamWizard::onUserSelectResolution(QSize newSize) { blog(LOG_INFO, "Selected res %d x %d", newSize.width(), newSize.height()); - EncoderSettingsRequest *req = currentSettings_.get(); + EncoderSettingsRequest *req = currentSettings_.data(); req->userSelectedResolution = QVariant(newSize); } diff --git a/UI/pre-stream-wizard/setting-selection-row.cpp b/UI/pre-stream-wizard/setting-selection-row.cpp index a6bd17b1a693a8..86fe8012b07880 100644 --- a/UI/pre-stream-wizard/setting-selection-row.cpp +++ b/UI/pre-stream-wizard/setting-selection-row.cpp @@ -8,10 +8,6 @@ SelectionRow::SelectionRow(QWidget *parent) : QWidget(parent) { createLayout(); } -SelectionRow::~SelectionRow() -{ - // nop -} void SelectionRow::createLayout() { diff --git a/UI/pre-stream-wizard/setting-selection-row.hpp b/UI/pre-stream-wizard/setting-selection-row.hpp index 0107c1ea1f6484..18a8d0dfa531fc 100644 --- a/UI/pre-stream-wizard/setting-selection-row.hpp +++ b/UI/pre-stream-wizard/setting-selection-row.hpp @@ -21,7 +21,6 @@ class SelectionRow : public QWidget { public: SelectionRow(QWidget *parent = nullptr); - ~SelectionRow(); // User facing name to be shown to the user. ("Resolution") void setName(QString newName); diff --git a/UI/streaming-settings-util.cpp b/UI/streaming-settings-util.cpp index 2e6864d15157ef..6d1efb3a40ea77 100644 --- a/UI/streaming-settings-util.cpp +++ b/UI/streaming-settings-util.cpp @@ -39,6 +39,7 @@ StreamingSettingsUtility::makeEncoderSettingsFromCurrentState( new StreamWizard::EncoderSettingsRequest()); /* Stream info */ + currentSettings->videoType = StreamWizard::VideoType::live; // only live and rmpts is supported for now currentSettings->protocol = StreamWizard::StreamProtocol::rtmps; @@ -56,7 +57,6 @@ StreamingSettingsUtility::makeEncoderSettingsFromCurrentState( currentSettings->videoHeight = resolutionXY[1]; currentSettings->framerate = CommonSettings::GetConfigFPSDouble(config); - // This ONLY works for simple output right now. If they're in advanced: no currentSettings->videoBitrate = CommonSettings::GetVideoBitrateInUse(config); currentSettings->videoCodec = StreamWizard::VideoCodec::h264;