Skip to content

Commit

Permalink
simplify implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
FrogTheFrog committed Jul 28, 2024
1 parent 04af34f commit 58c729d
Show file tree
Hide file tree
Showing 6 changed files with 52 additions and 93 deletions.
40 changes: 22 additions & 18 deletions src/display_device.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
#include <display_device/retry_scheduler.h>
#include <display_device/settings_manager_interface.h>

// local includes
#include "platform/common.h"

// platform-specific includes
#ifdef _WIN32
#include <display_device/windows/settings_manager.h>
Expand All @@ -19,6 +22,15 @@

namespace display_device {
namespace {
/**
* @brief A global for the settings manager interface whose lifetime is managed by `display_device::init()`.
*/
std::unique_ptr<RetryScheduler<SettingsManagerInterface>> SM_INSTANCE;

/**
* @brief Construct a settings manager interface to manage display device settings.
* @return An interface or nullptr if the OS does not support the interface.
*/
std::unique_ptr<SettingsManagerInterface>
make_settings_manager() {
#ifdef _WIN32
Expand All @@ -33,23 +45,17 @@ namespace display_device {
}
} // namespace

session_t &
session_t::get() {
static session_t session;
return session;
}

std::unique_ptr<platf::deinit_t>
session_t::init() {
init() {
// We can support re-init without any issues, however we should make sure to cleanup first!
get().impl = nullptr;
SM_INSTANCE = nullptr;

// If we fail to create settings manager, this means platform is not supported and
// we will need to provided error-free passtrough in other methods
if (auto settings_manager { make_settings_manager() }) {
get().impl = std::make_unique<RetryScheduler<SettingsManagerInterface>>(std::move(settings_manager));
SM_INSTANCE = std::make_unique<RetryScheduler<SettingsManagerInterface>>(std::move(settings_manager));

const auto available_devices { get().impl->execute([](auto &settings_iface) { return settings_iface.enumAvailableDevices(); }) };
const auto available_devices { SM_INSTANCE->execute([](auto &settings_iface) { return settings_iface.enumAvailableDevices(); }) };
BOOST_LOG(info) << "Currently available display devices:\n"
<< toJson(available_devices);

Expand All @@ -60,21 +66,19 @@ namespace display_device {
public:
~deinit_t() override {
// TODO: In the upcoming PR, execute recovery once here
get().impl = nullptr;
SM_INSTANCE = nullptr;
}
};
return std::make_unique<deinit_t>();
}

std::string
session_t::map_output_name(const std::string &output_name) const {
if (impl) {
return impl->execute([&output_name](auto &settings_iface) { return settings_iface.getDisplayName(output_name); });
map_output_name(const std::string &output_name) {
if (!SM_INSTANCE) {
// Fallback to giving back the output name if the platform is not supported.
return output_name;
}

// Fallback to giving back the output name if the platform is not supported.
return output_name;
return SM_INSTANCE->execute([&output_name](auto &settings_iface) { return settings_iface.getDisplayName(output_name); });
}

session_t::session_t() = default;
} // namespace display_device
93 changes: 24 additions & 69 deletions src/display_device.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,81 +4,36 @@
*/
#pragma once

// local includes
#include "platform/common.h"
// lib includes
#include <memory>

// forward declarations
namespace display_device {
template <class T>
class RetryScheduler;
class SettingsManagerInterface;
} // namespace display_device
namespace platf {
class deinit_t;
} // namespace platf

namespace display_device {
/**
* @brief A singleton class for managing the display device configuration for the whole Sunshine session.
* @brief Initialize the implementation and perform the initial state recovery (if needed).
* @returns A deinit_t instance that performs cleanup when destroyed.
*
* This class is meant to be an entry point for applying the configuration and reverting it later
* from within the various places in the Sunshine's source code.
* @examples
* const auto init_guard { display_device::init() };
* @examples_end
*/
class session_t {
public:
/**
* @brief Get the singleton instance.
* @returns Singleton instance for the class.
*
* @examples
* session_t& session { session_t::get() };
* @examples_end
*/
[[nodiscard]] static session_t &
get();

/**
* @brief Initialize the singleton and perform the initial state recovery (if needed).
* @returns A deinit_t instance that performs cleanup when destroyed.
*
* @examples
* const auto session_guard { session_t::init() };
* @examples_end
*/
[[nodiscard]] static std::unique_ptr<platf::deinit_t>
init();

/**
* @brief Map the output name to a specific display.
* @param output_name The user-configurable output name.
* @returns Mapped display name or empty string if the output name could not be mapped.
*
* @examples
* session_t& session { session_t::get() };
* const auto mapped_name_config { session.get_display_name(config::video.output_name) };
* const auto mapped_name_custom { session.get_display_name("{some-device-id}") };
* @examples_end
*/
[[nodiscard]] std::string
map_output_name(const std::string &output_name) const;

/**
* @brief A deleted copy constructor for singleton pattern.
* @note Public to ensure better error message.
*/
session_t(session_t const &) = delete;
std::unique_ptr<platf::deinit_t>
init();

/**
* @brief A deleted assignment operator for singleton pattern.
* @note Public to ensure better error message.
*/
void
operator=(session_t const &) = delete;

private:
/**
* @brief A private constructor to ensure the singleton pattern.
* @note Cannot be defaulted in declaration because of forward declared RetryScheduler.
*/
explicit session_t();

std::unique_ptr<RetryScheduler<SettingsManagerInterface>> impl; /**< Platform specific interface for managing settings (with retry functionality). */
};
/**
* @brief Map the output name to a specific display.
* @param output_name The user-configurable output name.
* @returns Mapped display name or empty string if the output name could not be mapped.
*
* @examples
* const auto mapped_name_config { map_output_name(config::video.output_name) };
* const auto mapped_name_custom { map_output_name("{some-device-id}") };
* @examples_end
*/
std::string
map_output_name(const std::string &output_name);
} // namespace display_device
2 changes: 1 addition & 1 deletion src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ main(int argc, char *argv[]) {
// Adding guard here first as it also performs recovery after crash,
// otherwise people could theoretically end up without display output.
// It also should be destroyed before forced shutdown to expedite the cleanup.
auto display_device_deinit_guard = display_device::session_t::init();
auto display_device_deinit_guard = display_device::init();
if (!display_device_deinit_guard) {
BOOST_LOG(error) << "Display device session failed to initialize"sv;
}
Expand Down
2 changes: 1 addition & 1 deletion src/platform/macos/input.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -539,7 +539,7 @@ const KeyCodeMap kKeyCodesMap[] = {
// Default to main display
macos_input->display = CGMainDisplayID();

auto output_name = display_device::session_t::get().map_output_name(config::video.output_name);
auto output_name = display_device::map_output_name(config::video.output_name);
// If output_name is set, try to find the display with that display id
if (!output_name.empty()) {
uint32_t max_display = 32;
Expand Down
2 changes: 1 addition & 1 deletion src/platform/windows/display_base.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1080,7 +1080,7 @@ namespace platf {
BOOST_LOG(debug) << "Detecting monitors..."sv;

// We must set the GPU preference before calling any DXGI APIs!
const auto output_name { display_device::session_t::get().map_output_name(config::video.output_name) };
const auto output_name { display_device::map_output_name(config::video.output_name) };
if (!dxgi::probe_for_gpu_preference(output_name)) {
BOOST_LOG(warning) << "Failed to set GPU preference. Capture may not work!"sv;
}
Expand Down
6 changes: 3 additions & 3 deletions src/video.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -968,7 +968,7 @@ namespace video {
void
refresh_displays(platf::mem_type_e dev_type, std::vector<std::string> &display_names, int &current_display_index) {
// It is possible that the output name may be empty even if it wasn't before (device disconnected) or vice-versa
const auto output_name { display_device::session_t::get().map_output_name(config::video.output_name) };
const auto output_name { display_device::map_output_name(config::video.output_name) };
std::string current_display_name;

// If we have a current display index, let's start with that
Expand Down Expand Up @@ -2291,7 +2291,7 @@ namespace video {

bool
validate_encoder(encoder_t &encoder, bool expect_failure) {
const auto output_name { display_device::session_t::get().map_output_name(config::video.output_name) };
const auto output_name { display_device::map_output_name(config::video.output_name) };
std::shared_ptr<platf::display_t> disp;

BOOST_LOG(info) << "Trying encoder ["sv << encoder.name << ']';
Expand Down Expand Up @@ -2595,7 +2595,7 @@ namespace video {
}

if (chosen_encoder == nullptr) {
const auto output_name { display_device::session_t::get().map_output_name(config::video.output_name) };
const auto output_name { display_device::map_output_name(config::video.output_name) };
BOOST_LOG(fatal) << "Unable to find display or encoder during startup."sv;
if (!config::video.adapter_name.empty() || !output_name.empty()) {
BOOST_LOG(fatal) << "Please ensure your manually chosen GPU and monitor are connected and powered on."sv;
Expand Down

0 comments on commit 58c729d

Please sign in to comment.