Skip to content

Commit

Permalink
feat: Add libdisplaydevice dependency and output name mapping
Browse files Browse the repository at this point in the history
  • Loading branch information
FrogTheFrog committed Jul 19, 2024
1 parent f694137 commit 9a8d7bb
Show file tree
Hide file tree
Showing 17 changed files with 310 additions and 59 deletions.
4 changes: 4 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@
path = third-party/inputtino
url = https://github.com/games-on-whales/inputtino.git
branch = stable
[submodule "third-party/libdisplaydevice"]
path = third-party/libdisplaydevice
url = https://github.com/LizardByte/libdisplaydevice.git
branch = master
[submodule "third-party/moonlight-common-c"]
path = third-party/moonlight-common-c
url = https://github.com/moonlight-stream/moonlight-common-c.git
Expand Down
5 changes: 4 additions & 1 deletion cmake/compile_definitions/common.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ set(SUNSHINE_TARGET_FILES
"${CMAKE_SOURCE_DIR}/src/uuid.h"
"${CMAKE_SOURCE_DIR}/src/config.h"
"${CMAKE_SOURCE_DIR}/src/config.cpp"
"${CMAKE_SOURCE_DIR}/src/display_device.h"
"${CMAKE_SOURCE_DIR}/src/display_device.cpp"
"${CMAKE_SOURCE_DIR}/src/entry_handler.cpp"
"${CMAKE_SOURCE_DIR}/src/entry_handler.h"
"${CMAKE_SOURCE_DIR}/src/file_handler.cpp"
Expand Down Expand Up @@ -137,4 +139,5 @@ list(APPEND SUNSHINE_EXTERNAL_LIBRARIES
${FFMPEG_LIBRARIES}
${Boost_LIBRARIES}
${OPENSSL_LIBRARIES}
${PLATFORM_LIBRARIES})
${PLATFORM_LIBRARIES}
libdisplaydevice::display_device)
3 changes: 3 additions & 0 deletions cmake/dependencies/common.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ add_subdirectory("${CMAKE_SOURCE_DIR}/third-party/moonlight-common-c/enet")
# web server
add_subdirectory("${CMAKE_SOURCE_DIR}/third-party/Simple-Web-Server")

# libdisplaydevice
add_subdirectory("${CMAKE_SOURCE_DIR}/third-party/libdisplaydevice")

# common dependencies
find_package(OpenSSL REQUIRED)
find_package(PkgConfig REQUIRED)
Expand Down
57 changes: 53 additions & 4 deletions docs/source/about/advanced_usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -586,7 +586,7 @@ keybindings
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

**Description**
Select the display number you want to stream.
Select the display you want to stream.

.. tip:: To find the name of the appropriate values follow these instructions.

Expand Down Expand Up @@ -616,9 +616,58 @@ keybindings
You need to use the id value inside the parenthesis, e.g. ``3``.

**Windows**
.. code-block:: batch
During Sunshine startup, you should see the list of detected displays:

tools\dxgi-info.exe
.. code-block:: text
Info: Currently available display devices:
[
{
"device_id": "{64243705-4020-5895-b923-adc862c3457e}",
"display_name": "",
"friendly_name": "IDD HDR",
"info": null
},
{
"device_id": "{77f67f3e-754f-5d31-af64-ee037e18100a}",
"display_name": "",
"friendly_name": "SunshineHDR",
"info": null
},
{
"device_id": "{daeac860-f4db-5208-b1f5-cf59444fb768}",
"display_name": "\\\\.\\DISPLAY1",
"friendly_name": "ROG PG279Q",
"info": {
"hdr_state": null,
"origin_point": {
"x": 0,
"y": 0
},
"primary": true,
"refresh_rate": {
"type": "rational",
"value": {
"denominator": 1000,
"numerator": 119998
}
},
"resolution": {
"height": 1440,
"width": 2560
},
"resolution_scale": {
"type": "rational",
"value": {
"denominator": 100,
"numerator": 100
}
}
}
}
]
You need to use the ``device_id`` value.

**Default**
Sunshine will select the default display.
Expand All @@ -637,7 +686,7 @@ keybindings
**Windows**
.. code-block:: text
output_name = \\.\DISPLAY1
output_name = {daeac860-f4db-5208-b1f5-cf59444fb768}
`resolutions <https://localhost:47990/config/#resolutions>`__
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down
80 changes: 80 additions & 0 deletions src/display_device.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/**
* @file src/display_device.cpp
* @brief Definitions for display device handling.
*/
// header include
#include "display_device.h"

// lib includes
#include <display_device/json.h>
#include <display_device/retry_scheduler.h>
#include <display_device/settings_manager_interface.h>

// platform-specific includes
#ifdef _WIN32
#include <display_device/windows/settings_manager.h>
#include <display_device/windows/win_api_layer.h>
#include <display_device/windows/win_display_device.h>
#endif

namespace display_device {
namespace {
std::unique_ptr<SettingsManagerInterface>
make_settings_manager() {
#ifdef _WIN32
// TODO: In the upcoming PR, add audio context capture and settings persistence
return std::make_unique<SettingsManager>(
std::make_shared<WinDisplayDevice>(std::make_shared<WinApiLayer>()),
nullptr,
std::make_unique<PersistentState>(nullptr));
#else
return nullptr;
#endif
}
} // namespace

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

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

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

// TODO: In the upcoming PR, schedule recovery here
}

class deinit_t: public platf::deinit_t {
public:
~deinit_t() override {
// TODO: In the upcoming PR, execute recovery once here
get().impl = 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); });
}

// Fallback to giving back the output name if the platform is not supported.
return output_name;
}

session_t::session_t() = default;
} // namespace display_device
87 changes: 87 additions & 0 deletions src/display_device.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/**
* @file src/display_device.h
* @brief Declarations for display device handling.
*/
#pragma once

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

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

namespace display_device {
/**
* @brief A singleton class for managing the display device configuration for the whole Sunshine session.
*
* 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.
*/
class session_t {
public:
/**
* @brief Get the singleton instance.
* @returns Singleton instance for the class.
*
* EXAMPLES:
* ```cpp
* session_t& session { session_t::get() };
* ```
*/
[[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:
* ```cpp
* const auto session_guard { session_t::init() };
* ```
*/
[[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:
* ```cpp
* 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}") };
* ```
*/
[[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;

/**
* @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). */
};
} // namespace display_device
32 changes: 32 additions & 0 deletions src/logging.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include <boost/log/expressions.hpp>
#include <boost/log/sinks.hpp>
#include <boost/log/sources/severity_logger.hpp>
#include <display_device/logging.h>

// local includes
#include "logging.h"
Expand Down Expand Up @@ -56,6 +57,7 @@ namespace logging {
}

setup_av_logging(min_log_level);
setup_libdisplaydevice_logging(min_log_level);

sink = boost::make_shared<text_sink>();

Expand Down Expand Up @@ -142,6 +144,36 @@ namespace logging {
});
}

void
setup_libdisplaydevice_logging(int min_log_level) {
constexpr int max_level { static_cast<int>(display_device::Logger::LogLevel::fatal) };
const auto log_level { static_cast<display_device::Logger::LogLevel>(min_log_level <= max_level ? min_log_level : max_level) };

display_device::Logger::get().setLogLevel(log_level);
display_device::Logger::get().setCustomCallback([](const display_device::Logger::LogLevel level, const std::string &message) {
switch (level) {
case display_device::Logger::LogLevel::verbose:
BOOST_LOG(verbose) << message;
break;
case display_device::Logger::LogLevel::debug:
BOOST_LOG(debug) << message;
break;
case display_device::Logger::LogLevel::info:
BOOST_LOG(info) << message;
break;
case display_device::Logger::LogLevel::warning:
BOOST_LOG(warning) << message;
break;
case display_device::Logger::LogLevel::error:
BOOST_LOG(error) << message;
break;
case display_device::Logger::LogLevel::fatal:
BOOST_LOG(fatal) << message;
break;
}
});
}

void
log_flush() {
if (sink) {
Expand Down
7 changes: 7 additions & 0 deletions src/logging.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,13 @@ namespace logging {
void
setup_av_logging(int min_log_level);

/**
* @brief Setup logging for libdisplaydevice.
* @param min_log_level The log level.
*/
void
setup_libdisplaydevice_logging(int min_log_level);

/**
* @brief Flush the log.
* @examples
Expand Down
Loading

0 comments on commit 9a8d7bb

Please sign in to comment.