123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900 |
- /******************************************************************************
- Copyright (C) 2023 by Lain Bailey <lain@obsproject.com>
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 2 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
- ******************************************************************************/
- #include <filesystem>
- #include <functional>
- #include <string>
- #include <map>
- #include <tuple>
- #include <obs.hpp>
- #include <util/platform.h>
- #include <util/util.hpp>
- #include <QMessageBox>
- #include <QVariant>
- #include <QFileDialog>
- #include <qt-wrappers.hpp>
- #include "window-basic-main.hpp"
- #include "window-basic-auto-config.hpp"
- #include "window-namedialog.hpp"
- // MARK: Constant Expressions
- constexpr std::string_view OBSProfilePath = "/obs-studio/basic/profiles/";
- constexpr std::string_view OBSProfileSettingsFile = "basic.ini";
- // MARK: Forward Declarations
- extern void DestroyPanelCookieManager();
- extern void DuplicateCurrentCookieProfile(ConfigFile &config);
- extern void CheckExistingCookieId();
- extern void DeleteCookies();
- // MARK: - Anonymous Namespace
- namespace {
- QList<QString> sortedProfiles{};
- void updateSortedProfiles(const OBSProfileCache &profiles)
- {
- const QLocale locale = QLocale::system();
- QList<QString> newList{};
- for (auto [profileName, _] : profiles) {
- QString entry = QString::fromStdString(profileName);
- newList.append(entry);
- }
- std::sort(newList.begin(), newList.end(), [&locale](const QString &lhs, const QString &rhs) -> bool {
- int result = QString::localeAwareCompare(locale.toLower(lhs), locale.toLower(rhs));
- return (result < 0);
- });
- sortedProfiles.swap(newList);
- }
- } // namespace
- // MARK: - Main Profile Management Functions
- void OBSBasic::SetupNewProfile(const std::string &profileName, bool useWizard)
- {
- const OBSProfile &newProfile = CreateProfile(profileName);
- config_set_bool(App()->GetUserConfig(), "Basic", "ConfigOnNewProfile", useWizard);
- ActivateProfile(newProfile, true);
- blog(LOG_INFO, "Created profile '%s' (clean, %s)", newProfile.name.c_str(), newProfile.directoryName.c_str());
- blog(LOG_INFO, "------------------------------------------------");
- if (useWizard) {
- AutoConfig wizard(this);
- wizard.setModal(true);
- wizard.show();
- wizard.exec();
- }
- }
- void OBSBasic::SetupDuplicateProfile(const std::string &profileName)
- {
- const OBSProfile &newProfile = CreateProfile(profileName);
- const OBSProfile ¤tProfile = GetCurrentProfile();
- const auto copyOptions = std::filesystem::copy_options::recursive |
- std::filesystem::copy_options::overwrite_existing;
- try {
- std::filesystem::copy(currentProfile.path, newProfile.path, copyOptions);
- } catch (const std::filesystem::filesystem_error &error) {
- blog(LOG_DEBUG, "%s", error.what());
- throw std::logic_error("Failed to copy files for cloned profile: " + newProfile.name);
- }
- ActivateProfile(newProfile);
- blog(LOG_INFO, "Created profile '%s' (duplicate, %s)", newProfile.name.c_str(),
- newProfile.directoryName.c_str());
- blog(LOG_INFO, "------------------------------------------------");
- }
- void OBSBasic::SetupRenameProfile(const std::string &profileName)
- {
- const OBSProfile &newProfile = CreateProfile(profileName);
- const OBSProfile currentProfile = GetCurrentProfile();
- const auto copyOptions = std::filesystem::copy_options::recursive |
- std::filesystem::copy_options::overwrite_existing;
- try {
- std::filesystem::copy(currentProfile.path, newProfile.path, copyOptions);
- } catch (const std::filesystem::filesystem_error &error) {
- blog(LOG_DEBUG, "%s", error.what());
- throw std::logic_error("Failed to copy files for profile: " + currentProfile.name);
- }
- profiles.erase(currentProfile.name);
- ActivateProfile(newProfile);
- RemoveProfile(currentProfile);
- blog(LOG_INFO, "Renamed profile '%s' to '%s' (%s)", currentProfile.name.c_str(), newProfile.name.c_str(),
- newProfile.directoryName.c_str());
- blog(LOG_INFO, "------------------------------------------------");
- OnEvent(OBS_FRONTEND_EVENT_PROFILE_RENAMED);
- }
- // MARK: - Profile File Management Functions
- const OBSProfile &OBSBasic::CreateProfile(const std::string &profileName)
- {
- if (const auto &foundProfile = GetProfileByName(profileName)) {
- throw std::invalid_argument("Profile already exists: " + profileName);
- }
- std::string directoryName;
- if (!GetFileSafeName(profileName.c_str(), directoryName)) {
- throw std::invalid_argument("Failed to create safe directory for new profile: " + profileName);
- }
- std::string profileDirectory;
- profileDirectory.reserve(App()->userProfilesLocation.u8string().size() + OBSProfilePath.size() +
- directoryName.size());
- profileDirectory.append(App()->userProfilesLocation.u8string()).append(OBSProfilePath).append(directoryName);
- if (!GetClosestUnusedFileName(profileDirectory, nullptr)) {
- throw std::invalid_argument("Failed to get closest directory name for new profile: " + profileName);
- }
- const std::filesystem::path profileDirectoryPath = std::filesystem::u8path(profileDirectory);
- try {
- std::filesystem::create_directory(profileDirectoryPath);
- } catch (const std::filesystem::filesystem_error error) {
- throw std::logic_error("Failed to create directory for new profile: " + profileDirectory);
- }
- const std::filesystem::path profileFile =
- profileDirectoryPath / std::filesystem::u8path(OBSProfileSettingsFile);
- auto [iterator, success] =
- profiles.try_emplace(profileName, OBSProfile{profileName, profileDirectoryPath.filename().u8string(),
- profileDirectoryPath, profileFile});
- OnEvent(OBS_FRONTEND_EVENT_PROFILE_LIST_CHANGED);
- return iterator->second;
- }
- void OBSBasic::RemoveProfile(OBSProfile profile)
- {
- try {
- std::filesystem::remove_all(profile.path);
- } catch (const std::filesystem::filesystem_error &error) {
- blog(LOG_DEBUG, "%s", error.what());
- throw std::logic_error("Failed to remove profile directory: " + profile.directoryName);
- }
- blog(LOG_INFO, "------------------------------------------------");
- blog(LOG_INFO, "Removed profile '%s' (%s)", profile.name.c_str(), profile.directoryName.c_str());
- blog(LOG_INFO, "------------------------------------------------");
- }
- // MARK: - Profile UI Handling Functions
- bool OBSBasic::CreateNewProfile(const QString &name)
- {
- try {
- SetupNewProfile(name.toStdString());
- return true;
- } catch (const std::invalid_argument &error) {
- blog(LOG_ERROR, "%s", error.what());
- return false;
- } catch (const std::logic_error &error) {
- blog(LOG_ERROR, "%s", error.what());
- return false;
- }
- }
- bool OBSBasic::CreateDuplicateProfile(const QString &name)
- {
- try {
- SetupDuplicateProfile(name.toStdString());
- return true;
- } catch (const std::invalid_argument &error) {
- blog(LOG_ERROR, "%s", error.what());
- return false;
- } catch (const std::logic_error &error) {
- blog(LOG_ERROR, "%s", error.what());
- return false;
- }
- }
- void OBSBasic::DeleteProfile(const QString &name)
- {
- const std::string_view currentProfileName{config_get_string(App()->GetUserConfig(), "Basic", "Profile")};
- if (currentProfileName == name.toStdString()) {
- on_actionRemoveProfile_triggered();
- return;
- }
- auto foundProfile = GetProfileByName(name.toStdString());
- if (!foundProfile) {
- blog(LOG_ERROR, "Invalid profile name: %s", QT_TO_UTF8(name));
- return;
- }
- RemoveProfile(foundProfile.value());
- profiles.erase(name.toStdString());
- RefreshProfiles();
- config_save_safe(App()->GetUserConfig(), "tmp", nullptr);
- OnEvent(OBS_FRONTEND_EVENT_PROFILE_LIST_CHANGED);
- }
- void OBSBasic::ChangeProfile()
- {
- QAction *action = reinterpret_cast<QAction *>(sender());
- if (!action) {
- return;
- }
- const std::string_view currentProfileName{config_get_string(App()->GetUserConfig(), "Basic", "Profile")};
- const QVariant qProfileName = action->property("profile_name");
- const std::string selectedProfileName{qProfileName.toString().toStdString()};
- if (currentProfileName == selectedProfileName) {
- action->setChecked(true);
- return;
- }
- const std::optional<OBSProfile> foundProfile = GetProfileByName(selectedProfileName);
- if (!foundProfile) {
- const std::string errorMessage{"Selected profile not found: "};
- throw std::invalid_argument(errorMessage + selectedProfileName.data());
- }
- const OBSProfile &selectedProfile = foundProfile.value();
- OnEvent(OBS_FRONTEND_EVENT_PROFILE_CHANGING);
- ActivateProfile(selectedProfile, true);
- blog(LOG_INFO, "Switched to profile '%s' (%s)", selectedProfile.name.c_str(),
- selectedProfile.directoryName.c_str());
- blog(LOG_INFO, "------------------------------------------------");
- }
- void OBSBasic::RefreshProfiles(bool refreshCache)
- {
- std::string_view currentProfileName{config_get_string(App()->GetUserConfig(), "Basic", "Profile")};
- QList<QAction *> menuActions = ui->profileMenu->actions();
- for (auto &action : menuActions) {
- QVariant variant = action->property("file_name");
- if (variant.typeName() != nullptr) {
- delete action;
- }
- }
- if (refreshCache) {
- RefreshProfileCache();
- }
- updateSortedProfiles(profiles);
- size_t numAddedProfiles = 0;
- for (auto &name : sortedProfiles) {
- const std::string profileName = name.toStdString();
- try {
- const OBSProfile &profile = profiles.at(profileName);
- const QString qProfileName = QString().fromStdString(profileName);
- QAction *action = new QAction(qProfileName, this);
- action->setProperty("profile_name", qProfileName);
- action->setProperty("file_name", QString().fromStdString(profile.directoryName));
- connect(action, &QAction::triggered, this, &OBSBasic::ChangeProfile);
- action->setCheckable(true);
- action->setChecked(profileName == currentProfileName);
- ui->profileMenu->addAction(action);
- numAddedProfiles += 1;
- } catch (const std::out_of_range &error) {
- blog(LOG_ERROR, "No profile with name %s found in profile cache.\n%s", profileName.c_str(),
- error.what());
- }
- }
- ui->actionRemoveProfile->setEnabled(numAddedProfiles > 1);
- }
- // MARK: - Profile Cache Functions
- /// Refreshes profile cache data with profile state found on local file system.
- void OBSBasic::RefreshProfileCache()
- {
- std::map<std::string, OBSProfile> foundProfiles{};
- const std::filesystem::path profilesPath =
- App()->userProfilesLocation / std::filesystem::u8path(OBSProfilePath.substr(1));
- const std::filesystem::path profileSettingsFile = std::filesystem::u8path(OBSProfileSettingsFile);
- if (!std::filesystem::exists(profilesPath)) {
- blog(LOG_WARNING, "Failed to get profiles config path");
- return;
- }
- for (const auto &entry : std::filesystem::directory_iterator(profilesPath)) {
- if (!entry.is_directory()) {
- continue;
- }
- const auto profileCandidate = entry.path() / profileSettingsFile;
- ConfigFile config;
- if (config.Open(profileCandidate.u8string().c_str(), CONFIG_OPEN_EXISTING) != CONFIG_SUCCESS) {
- continue;
- }
- std::string candidateName;
- const char *configName = config_get_string(config, "General", "Name");
- if (configName) {
- candidateName = configName;
- } else {
- candidateName = entry.path().filename().u8string();
- }
- foundProfiles.try_emplace(candidateName, OBSProfile{candidateName, entry.path().filename().u8string(),
- entry.path(), profileCandidate});
- }
- profiles.swap(foundProfiles);
- }
- const OBSProfile &OBSBasic::GetCurrentProfile() const
- {
- std::string currentProfileName{config_get_string(App()->GetUserConfig(), "Basic", "Profile")};
- if (currentProfileName.empty()) {
- throw std::invalid_argument("No valid profile name in configuration Basic->Profile");
- }
- const auto &foundProfile = profiles.find(currentProfileName);
- if (foundProfile != profiles.end()) {
- return foundProfile->second;
- } else {
- throw std::invalid_argument("Profile not found in profile list: " + currentProfileName);
- }
- }
- std::optional<OBSProfile> OBSBasic::GetProfileByName(const std::string &profileName) const
- {
- auto foundProfile = profiles.find(profileName);
- if (foundProfile == profiles.end()) {
- return {};
- } else {
- return foundProfile->second;
- }
- }
- std::optional<OBSProfile> OBSBasic::GetProfileByDirectoryName(const std::string &directoryName) const
- {
- for (auto &[iterator, profile] : profiles) {
- if (profile.directoryName == directoryName) {
- return profile;
- }
- }
- return {};
- }
- // MARK: - Qt Slot Functions
- void OBSBasic::on_actionNewProfile_triggered()
- {
- bool useProfileWizard = config_get_bool(App()->GetUserConfig(), "Basic", "ConfigOnNewProfile");
- const OBSPromptCallback profilePromptCallback = [this](const OBSPromptResult &result) {
- if (GetProfileByName(result.promptValue)) {
- return false;
- }
- return true;
- };
- const OBSPromptRequest request{Str("AddProfile.Title"), Str("AddProfile.Text"), "", true,
- Str("AddProfile.WizardCheckbox"), useProfileWizard};
- OBSPromptResult result = PromptForName(request, profilePromptCallback);
- if (!result.success) {
- return;
- }
- try {
- SetupNewProfile(result.promptValue, result.optionValue);
- } catch (const std::invalid_argument &error) {
- blog(LOG_ERROR, "%s", error.what());
- } catch (const std::logic_error &error) {
- blog(LOG_ERROR, "%s", error.what());
- }
- }
- void OBSBasic::on_actionDupProfile_triggered()
- {
- const OBSPromptCallback profilePromptCallback = [this](const OBSPromptResult &result) {
- if (GetProfileByName(result.promptValue)) {
- return false;
- }
- return true;
- };
- const OBSPromptRequest request{Str("AddProfile.Title"), Str("AddProfile.Text")};
- OBSPromptResult result = PromptForName(request, profilePromptCallback);
- if (!result.success) {
- return;
- }
- try {
- SetupDuplicateProfile(result.promptValue);
- } catch (const std::invalid_argument &error) {
- blog(LOG_ERROR, "%s", error.what());
- } catch (const std::logic_error &error) {
- blog(LOG_ERROR, "%s", error.what());
- }
- }
- void OBSBasic::on_actionRenameProfile_triggered()
- {
- const std::string currentProfileName = config_get_string(App()->GetUserConfig(), "Basic", "Profile");
- const OBSPromptCallback profilePromptCallback = [this](const OBSPromptResult &result) {
- if (GetProfileByName(result.promptValue)) {
- return false;
- }
- return true;
- };
- const OBSPromptRequest request{Str("RenameProfile.Title"), Str("AddProfile.Text"), currentProfileName};
- OBSPromptResult result = PromptForName(request, profilePromptCallback);
- if (!result.success) {
- return;
- }
- try {
- SetupRenameProfile(result.promptValue);
- } catch (const std::invalid_argument &error) {
- blog(LOG_ERROR, "%s", error.what());
- } catch (const std::logic_error &error) {
- blog(LOG_ERROR, "%s", error.what());
- }
- }
- void OBSBasic::on_actionRemoveProfile_triggered(bool skipConfirmation)
- {
- if (profiles.size() < 2) {
- return;
- }
- OBSProfile currentProfile;
- try {
- currentProfile = GetCurrentProfile();
- if (!skipConfirmation) {
- const QString confirmationText =
- QTStr("ConfirmRemove.Text").arg(QString::fromStdString(currentProfile.name));
- const QMessageBox::StandardButton button =
- OBSMessageBox::question(this, QTStr("ConfirmRemove.Title"), confirmationText);
- if (button == QMessageBox::No) {
- return;
- }
- }
- OnEvent(OBS_FRONTEND_EVENT_PROFILE_CHANGING);
- profiles.erase(currentProfile.name);
- } catch (const std::invalid_argument &error) {
- blog(LOG_ERROR, "%s", error.what());
- } catch (const std::logic_error &error) {
- blog(LOG_ERROR, "%s", error.what());
- }
- const OBSProfile &newProfile = profiles.begin()->second;
- ActivateProfile(newProfile, true);
- RemoveProfile(currentProfile);
- #ifdef YOUTUBE_ENABLED
- if (YouTubeAppDock::IsYTServiceSelected() && !youtubeAppDock)
- NewYouTubeAppDock();
- #endif
- blog(LOG_INFO, "Switched to profile '%s' (%s)", newProfile.name.c_str(), newProfile.directoryName.c_str());
- blog(LOG_INFO, "------------------------------------------------");
- }
- void OBSBasic::on_actionImportProfile_triggered()
- {
- const QString home = QDir::homePath();
- const QString sourceDirectory = SelectDirectory(this, QTStr("Basic.MainMenu.Profile.Import"), home);
- if (!sourceDirectory.isEmpty() && !sourceDirectory.isNull()) {
- const std::filesystem::path sourcePath = std::filesystem::u8path(sourceDirectory.toStdString());
- const std::string directoryName = sourcePath.filename().string();
- if (auto profile = GetProfileByDirectoryName(directoryName)) {
- OBSMessageBox::warning(this, QTStr("Basic.MainMenu.Profile.Import"),
- QTStr("Basic.MainMenu.Profile.Exists"));
- return;
- }
- std::string destinationPathString;
- destinationPathString.reserve(App()->userProfilesLocation.u8string().size() + OBSProfilePath.size() +
- directoryName.size());
- destinationPathString.append(App()->userProfilesLocation.u8string())
- .append(OBSProfilePath)
- .append(directoryName);
- const std::filesystem::path destinationPath = std::filesystem::u8path(destinationPathString);
- try {
- std::filesystem::create_directory(destinationPath);
- } catch (const std::filesystem::filesystem_error &error) {
- blog(LOG_WARNING, "Failed to create profile directory '%s':\n%s", directoryName.c_str(),
- error.what());
- return;
- }
- const std::array<std::pair<std::string, bool>, 4> profileFiles{{
- {"basic.ini", true},
- {"service.json", false},
- {"streamEncoder.json", false},
- {"recordEncoder.json", false},
- }};
- for (auto &[file, isMandatory] : profileFiles) {
- const std::filesystem::path sourceFile = sourcePath / std::filesystem::u8path(file);
- if (!std::filesystem::exists(sourceFile)) {
- if (isMandatory) {
- blog(LOG_ERROR,
- "Failed to import profile from directory '%s' - necessary file '%s' not found",
- directoryName.c_str(), file.c_str());
- return;
- }
- continue;
- }
- const std::filesystem::path destinationFile = destinationPath / std::filesystem::u8path(file);
- try {
- std::filesystem::copy(sourceFile, destinationFile);
- } catch (const std::filesystem::filesystem_error &error) {
- blog(LOG_WARNING, "Failed to copy import file '%s' for profile '%s':\n%s", file.c_str(),
- directoryName.c_str(), error.what());
- return;
- }
- }
- RefreshProfiles(true);
- }
- }
- void OBSBasic::on_actionExportProfile_triggered()
- {
- const OBSProfile ¤tProfile = GetCurrentProfile();
- const QString home = QDir::homePath();
- const QString destinationDirectory = SelectDirectory(this, QTStr("Basic.MainMenu.Profile.Export"), home);
- const std::array<std::string, 4> profileFiles{"basic.ini", "service.json", "streamEncoder.json",
- "recordEncoder.json"};
- if (!destinationDirectory.isEmpty() && !destinationDirectory.isNull()) {
- const std::filesystem::path sourcePath = currentProfile.path;
- const std::filesystem::path destinationPath =
- std::filesystem::u8path(destinationDirectory.toStdString()) /
- std::filesystem::u8path(currentProfile.directoryName);
- if (!std::filesystem::exists(destinationPath)) {
- std::filesystem::create_directory(destinationPath);
- }
- std::filesystem::copy_options copyOptions = std::filesystem::copy_options::overwrite_existing;
- for (auto &file : profileFiles) {
- const std::filesystem::path sourceFile = sourcePath / std::filesystem::u8path(file);
- if (!std::filesystem::exists(sourceFile)) {
- continue;
- }
- const std::filesystem::path destinationFile = destinationPath / std::filesystem::u8path(file);
- try {
- std::filesystem::copy(sourceFile, destinationFile, copyOptions);
- } catch (const std::filesystem::filesystem_error &error) {
- blog(LOG_WARNING, "Failed to copy export file '%s' for profile '%s'\n%s", file.c_str(),
- currentProfile.name.c_str(), error.what());
- return;
- }
- }
- }
- }
- // MARK: - Profile Management Helper Functions
- void OBSBasic::ActivateProfile(const OBSProfile &profile, bool reset)
- {
- ConfigFile config;
- if (config.Open(profile.profileFile.u8string().c_str(), CONFIG_OPEN_ALWAYS) != CONFIG_SUCCESS) {
- throw std::logic_error("failed to open configuration file of new profile: " +
- profile.profileFile.string());
- }
- config_set_string(config, "General", "Name", profile.name.c_str());
- config.SaveSafe("tmp");
- std::vector<std::string> restartRequirements;
- if (activeConfiguration) {
- Auth::Save();
- if (reset) {
- auth.reset();
- DestroyPanelCookieManager();
- #ifdef YOUTUBE_ENABLED
- if (youtubeAppDock) {
- DeleteYouTubeAppDock();
- }
- #endif
- }
- restartRequirements = GetRestartRequirements(config);
- activeConfiguration.SaveSafe("tmp");
- }
- activeConfiguration.Swap(config);
- config_set_string(App()->GetUserConfig(), "Basic", "Profile", profile.name.c_str());
- config_set_string(App()->GetUserConfig(), "Basic", "ProfileDir", profile.directoryName.c_str());
- config_save_safe(App()->GetUserConfig(), "tmp", nullptr);
- InitBasicConfigDefaults();
- InitBasicConfigDefaults2();
- if (reset) {
- ResetProfileData();
- }
- CheckForSimpleModeX264Fallback();
- RefreshProfiles();
- UpdateTitleBar();
- UpdateVolumeControlsDecayRate();
- Auth::Load();
- OnEvent(OBS_FRONTEND_EVENT_PROFILE_CHANGED);
- if (!restartRequirements.empty()) {
- std::string requirements = std::accumulate(
- std::next(restartRequirements.begin()), restartRequirements.end(), restartRequirements[0],
- [](std::string a, std::string b) { return std::move(a) + "\n" + b; });
- QMessageBox::StandardButton button = OBSMessageBox::question(
- this, QTStr("Restart"), QTStr("LoadProfileNeedsRestart").arg(requirements.c_str()));
- if (button == QMessageBox::Yes) {
- restart = true;
- close();
- }
- }
- }
- void OBSBasic::ResetProfileData()
- {
- ResetVideo();
- service = nullptr;
- InitService();
- ResetOutputs();
- ClearHotkeys();
- CreateHotkeys();
- /* load audio monitoring */
- if (obs_audio_monitoring_available()) {
- const char *device_name = config_get_string(activeConfiguration, "Audio", "MonitoringDeviceName");
- const char *device_id = config_get_string(activeConfiguration, "Audio", "MonitoringDeviceId");
- obs_set_audio_monitoring_device(device_name, device_id);
- blog(LOG_INFO, "Audio monitoring device:\n\tname: %s\n\tid: %s", device_name, device_id);
- }
- }
- std::vector<std::string> OBSBasic::GetRestartRequirements(const ConfigFile &config) const
- {
- std::vector<std::string> result;
- const char *oldSpeakers = config_get_string(activeConfiguration, "Audio", "ChannelSetup");
- const char *newSpeakers = config_get_string(config, "Audio", "ChannelSetup");
- uint64_t oldSampleRate = config_get_uint(activeConfiguration, "Audio", "SampleRate");
- uint64_t newSampleRate = config_get_uint(config, "Audio", "SampleRate");
- if (oldSpeakers != NULL && newSpeakers != NULL) {
- if (std::string_view{oldSpeakers} != std::string_view{newSpeakers}) {
- result.emplace_back(Str("Basic.Settings.Audio.Channels"));
- }
- }
- if (oldSampleRate != 0 && newSampleRate != 0) {
- if (oldSampleRate != newSampleRate) {
- result.emplace_back(Str("Basic.Settings.Audio.SampleRate"));
- }
- }
- return result;
- }
- void OBSBasic::CheckForSimpleModeX264Fallback()
- {
- const char *curStreamEncoder = config_get_string(activeConfiguration, "SimpleOutput", "StreamEncoder");
- const char *curRecEncoder = config_get_string(activeConfiguration, "SimpleOutput", "RecEncoder");
- bool qsv_supported = false;
- bool qsv_av1_supported = false;
- bool amd_supported = false;
- bool nve_supported = false;
- #ifdef ENABLE_HEVC
- bool amd_hevc_supported = false;
- bool nve_hevc_supported = false;
- bool apple_hevc_supported = false;
- #endif
- bool amd_av1_supported = false;
- bool apple_supported = false;
- bool changed = false;
- size_t idx = 0;
- const char *id;
- while (obs_enum_encoder_types(idx++, &id)) {
- if (strcmp(id, "h264_texture_amf") == 0)
- amd_supported = true;
- else if (strcmp(id, "obs_qsv11") == 0)
- qsv_supported = true;
- else if (strcmp(id, "obs_qsv11_av1") == 0)
- qsv_av1_supported = true;
- else if (strcmp(id, "ffmpeg_nvenc") == 0)
- nve_supported = true;
- #ifdef ENABLE_HEVC
- else if (strcmp(id, "h265_texture_amf") == 0)
- amd_hevc_supported = true;
- else if (strcmp(id, "ffmpeg_hevc_nvenc") == 0)
- nve_hevc_supported = true;
- #endif
- else if (strcmp(id, "av1_texture_amf") == 0)
- amd_av1_supported = true;
- else if (strcmp(id, "com.apple.videotoolbox.videoencoder.ave.avc") == 0)
- apple_supported = true;
- #ifdef ENABLE_HEVC
- else if (strcmp(id, "com.apple.videotoolbox.videoencoder.ave.hevc") == 0)
- apple_hevc_supported = true;
- #endif
- }
- auto CheckEncoder = [&](const char *&name) {
- if (strcmp(name, SIMPLE_ENCODER_QSV) == 0) {
- if (!qsv_supported) {
- changed = true;
- name = SIMPLE_ENCODER_X264;
- return false;
- }
- } else if (strcmp(name, SIMPLE_ENCODER_QSV_AV1) == 0) {
- if (!qsv_av1_supported) {
- changed = true;
- name = SIMPLE_ENCODER_X264;
- return false;
- }
- } else if (strcmp(name, SIMPLE_ENCODER_NVENC) == 0) {
- if (!nve_supported) {
- changed = true;
- name = SIMPLE_ENCODER_X264;
- return false;
- }
- } else if (strcmp(name, SIMPLE_ENCODER_NVENC_AV1) == 0) {
- if (!nve_supported) {
- changed = true;
- name = SIMPLE_ENCODER_X264;
- return false;
- }
- #ifdef ENABLE_HEVC
- } else if (strcmp(name, SIMPLE_ENCODER_AMD_HEVC) == 0) {
- if (!amd_hevc_supported) {
- changed = true;
- name = SIMPLE_ENCODER_X264;
- return false;
- }
- } else if (strcmp(name, SIMPLE_ENCODER_NVENC_HEVC) == 0) {
- if (!nve_hevc_supported) {
- changed = true;
- name = SIMPLE_ENCODER_X264;
- return false;
- }
- #endif
- } else if (strcmp(name, SIMPLE_ENCODER_AMD) == 0) {
- if (!amd_supported) {
- changed = true;
- name = SIMPLE_ENCODER_X264;
- return false;
- }
- } else if (strcmp(name, SIMPLE_ENCODER_AMD_AV1) == 0) {
- if (!amd_av1_supported) {
- changed = true;
- name = SIMPLE_ENCODER_X264;
- return false;
- }
- } else if (strcmp(name, SIMPLE_ENCODER_APPLE_H264) == 0) {
- if (!apple_supported) {
- changed = true;
- name = SIMPLE_ENCODER_X264;
- return false;
- }
- #ifdef ENABLE_HEVC
- } else if (strcmp(name, SIMPLE_ENCODER_APPLE_HEVC) == 0) {
- if (!apple_hevc_supported) {
- changed = true;
- name = SIMPLE_ENCODER_X264;
- return false;
- }
- #endif
- }
- return true;
- };
- if (!CheckEncoder(curStreamEncoder))
- config_set_string(activeConfiguration, "SimpleOutput", "StreamEncoder", curStreamEncoder);
- if (!CheckEncoder(curRecEncoder))
- config_set_string(activeConfiguration, "SimpleOutput", "RecEncoder", curRecEncoder);
- if (changed) {
- activeConfiguration.SaveSafe("tmp");
- }
- }
|