Skip to content

Commit 6487802

Browse files
committed
feat: Add libdisplaydevice dependency and output name mapping
1 parent d5854ae commit 6487802

File tree

20 files changed

+327
-101
lines changed

20 files changed

+327
-101
lines changed

.gitmodules

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@
2222
path = third-party/inputtino
2323
url = https://github.com/games-on-whales/inputtino.git
2424
branch = stable
25+
[submodule "third-party/libdisplaydevice"]
26+
path = third-party/libdisplaydevice
27+
url = https://github.com/LizardByte/libdisplaydevice.git
28+
branch = master
2529
[submodule "third-party/moonlight-common-c"]
2630
path = third-party/moonlight-common-c
2731
url = https://github.com/moonlight-stream/moonlight-common-c.git

cmake/compile_definitions/common.cmake

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ set(SUNSHINE_TARGET_FILES
6868
"${CMAKE_SOURCE_DIR}/src/uuid.h"
6969
"${CMAKE_SOURCE_DIR}/src/config.h"
7070
"${CMAKE_SOURCE_DIR}/src/config.cpp"
71+
"${CMAKE_SOURCE_DIR}/src/display_device.h"
72+
"${CMAKE_SOURCE_DIR}/src/display_device.cpp"
7173
"${CMAKE_SOURCE_DIR}/src/entry_handler.cpp"
7274
"${CMAKE_SOURCE_DIR}/src/entry_handler.h"
7375
"${CMAKE_SOURCE_DIR}/src/file_handler.cpp"
@@ -146,6 +148,7 @@ list(APPEND SUNSHINE_EXTERNAL_LIBRARIES
146148
${MINIUPNP_LIBRARIES}
147149
${CMAKE_THREAD_LIBS_INIT}
148150
enet
151+
libdisplaydevice::display_device
149152
opus
150153
${FFMPEG_LIBRARIES}
151154
${Boost_LIBRARIES}

cmake/dependencies/common.cmake

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ add_subdirectory("${CMAKE_SOURCE_DIR}/third-party/moonlight-common-c/enet")
1212
# web server
1313
add_subdirectory("${CMAKE_SOURCE_DIR}/third-party/Simple-Web-Server")
1414

15+
# libdisplaydevice
16+
add_subdirectory("${CMAKE_SOURCE_DIR}/third-party/libdisplaydevice")
17+
1518
# common dependencies
1619
find_package(OpenSSL REQUIRED)
1720
find_package(PkgConfig REQUIRED)

docs/configuration.md

Lines changed: 49 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -865,10 +865,56 @@ editing the `conf` file in a text editor. Use the examples as reference.
865865
<br>
866866
**Windows:**
867867
<br>
868-
Enter the following command in command prompt or PowerShell.
868+
During Sunshine startup, you should see the list of detected displays:
869869
@code{}
870-
%ProgramFiles%\Sunshine\tools\dxgi-info.exe
870+
Info: Currently available display devices:
871+
[
872+
{
873+
"device_id": "{64243705-4020-5895-b923-adc862c3457e}",
874+
"display_name": "",
875+
"friendly_name": "IDD HDR",
876+
"info": null
877+
},
878+
{
879+
"device_id": "{77f67f3e-754f-5d31-af64-ee037e18100a}",
880+
"display_name": "",
881+
"friendly_name": "SunshineHDR",
882+
"info": null
883+
},
884+
{
885+
"device_id": "{daeac860-f4db-5208-b1f5-cf59444fb768}",
886+
"display_name": "\\\\.\\DISPLAY1",
887+
"friendly_name": "ROG PG279Q",
888+
"info": {
889+
"hdr_state": null,
890+
"origin_point": {
891+
"x": 0,
892+
"y": 0
893+
},
894+
"primary": true,
895+
"refresh_rate": {
896+
"type": "rational",
897+
"value": {
898+
"denominator": 1000,
899+
"numerator": 119998
900+
}
901+
},
902+
"resolution": {
903+
"height": 1440,
904+
"width": 2560
905+
},
906+
"resolution_scale": {
907+
"type": "rational",
908+
"value": {
909+
"denominator": 100,
910+
"numerator": 100
911+
}
912+
}
913+
}
914+
}
915+
]
871916
@endcode
917+
You need to use the `device_id` value.
872918
}
873919
</td>
874920
</tr>
@@ -891,7 +937,7 @@ editing the `conf` file in a text editor. Use the examples as reference.
891937
<tr>
892938
<td>Example (Windows)</td>
893939
<td colspan="2">@code{}
894-
output_name = \\.\DISPLAY1
940+
output_name = {daeac860-f4db-5208-b1f5-cf59444fb768}
895941
@endcode</td>
896942
</tr>
897943
</table>

packaging/linux/flatpak/dev.lizardbyte.app.Sunshine.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ modules:
3232
# Test dependencies
3333
- "modules/xvfb/xvfb.json"
3434

35+
# Build dependencies
36+
- "modules/nlohmann_json.json"
37+
3538
# Runtime dependencies
3639
- shared-modules/libayatana-appindicator/libayatana-appindicator-gtk3.json
3740
- "modules/avahi.json"
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"name": "nlohmann_json",
3+
"buildsystem": "cmake-ninja",
4+
"config-opts": [
5+
"-DJSON_MultipleHeaders=OFF",
6+
"-DJSON_BuildTests=OFF"
7+
],
8+
"sources": [
9+
{
10+
"type": "archive",
11+
"url": "https://github.com/nlohmann/json/releases/download/v3.11.3/json.tar.xz",
12+
"sha256": "d6c65aca6b1ed68e7a182f4757257b107ae403032760ed6ef121c9d55e81757d"
13+
}
14+
]
15+
}

src/display_device.cpp

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
/**
2+
* @file src/display_device.cpp
3+
* @brief Definitions for display device handling.
4+
*/
5+
// header include
6+
#include "display_device.h"
7+
8+
// lib includes
9+
#include <display_device/json.h>
10+
#include <display_device/retry_scheduler.h>
11+
#include <display_device/settings_manager_interface.h>
12+
13+
// local includes
14+
#include "platform/common.h"
15+
16+
// platform-specific includes
17+
#ifdef _WIN32
18+
#include <display_device/windows/settings_manager.h>
19+
#include <display_device/windows/win_api_layer.h>
20+
#include <display_device/windows/win_display_device.h>
21+
#endif
22+
23+
namespace display_device {
24+
namespace {
25+
/**
26+
* @brief A global for the settings manager interface whose lifetime is managed by `display_device::init()`.
27+
*/
28+
std::unique_ptr<RetryScheduler<SettingsManagerInterface>> SM_INSTANCE;
29+
30+
/**
31+
* @brief Construct a settings manager interface to manage display device settings.
32+
* @return An interface or nullptr if the OS does not support the interface.
33+
*/
34+
std::unique_ptr<SettingsManagerInterface>
35+
make_settings_manager() {
36+
#ifdef _WIN32
37+
// TODO: In the upcoming PR, add audio context capture and settings persistence
38+
return std::make_unique<SettingsManager>(
39+
std::make_shared<WinDisplayDevice>(std::make_shared<WinApiLayer>()),
40+
nullptr,
41+
std::make_unique<PersistentState>(nullptr),
42+
WinWorkarounds {});
43+
#else
44+
return nullptr;
45+
#endif
46+
}
47+
} // namespace
48+
49+
std::unique_ptr<platf::deinit_t>
50+
init() {
51+
// We can support re-init without any issues, however we should make sure to cleanup first!
52+
SM_INSTANCE = nullptr;
53+
54+
// If we fail to create settings manager, this means platform is not supported and
55+
// we will need to provided error-free passtrough in other methods
56+
if (auto settings_manager { make_settings_manager() }) {
57+
SM_INSTANCE = std::make_unique<RetryScheduler<SettingsManagerInterface>>(std::move(settings_manager));
58+
59+
const auto available_devices { SM_INSTANCE->execute([](auto &settings_iface) { return settings_iface.enumAvailableDevices(); }) };
60+
BOOST_LOG(info) << "Currently available display devices:\n"
61+
<< toJson(available_devices);
62+
63+
// TODO: In the upcoming PR, schedule recovery here
64+
}
65+
66+
class deinit_t: public platf::deinit_t {
67+
public:
68+
~deinit_t() override {
69+
// TODO: In the upcoming PR, execute recovery once here
70+
SM_INSTANCE = nullptr;
71+
}
72+
};
73+
return std::make_unique<deinit_t>();
74+
}
75+
76+
std::string
77+
map_output_name(const std::string &output_name) {
78+
if (!SM_INSTANCE) {
79+
// Fallback to giving back the output name if the platform is not supported.
80+
return output_name;
81+
}
82+
83+
return SM_INSTANCE->execute([&output_name](auto &settings_iface) { return settings_iface.getDisplayName(output_name); });
84+
}
85+
} // namespace display_device

src/display_device.h

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/**
2+
* @file src/display_device.h
3+
* @brief Declarations for display device handling.
4+
*/
5+
#pragma once
6+
7+
// lib includes
8+
#include <memory>
9+
10+
// forward declarations
11+
namespace platf {
12+
class deinit_t;
13+
} // namespace platf
14+
15+
namespace display_device {
16+
/**
17+
* @brief Initialize the implementation and perform the initial state recovery (if needed).
18+
* @returns A deinit_t instance that performs cleanup when destroyed.
19+
*
20+
* @examples
21+
* const auto init_guard { display_device::init() };
22+
* @examples_end
23+
*/
24+
std::unique_ptr<platf::deinit_t>
25+
init();
26+
27+
/**
28+
* @brief Map the output name to a specific display.
29+
* @param output_name The user-configurable output name.
30+
* @returns Mapped display name or empty string if the output name could not be mapped.
31+
*
32+
* @examples
33+
* const auto mapped_name_config { map_output_name(config::video.output_name) };
34+
* const auto mapped_name_custom { map_output_name("{some-device-id}") };
35+
* @examples_end
36+
*/
37+
std::string
38+
map_output_name(const std::string &output_name);
39+
} // namespace display_device

src/logging.cpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include <boost/log/expressions.hpp>
1616
#include <boost/log/sinks.hpp>
1717
#include <boost/log/sources/severity_logger.hpp>
18+
#include <display_device/logging.h>
1819

1920
// local includes
2021
#include "logging.h"
@@ -106,6 +107,7 @@ namespace logging {
106107
}
107108

108109
setup_av_logging(min_log_level);
110+
setup_libdisplaydevice_logging(min_log_level);
109111

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

@@ -159,6 +161,37 @@ namespace logging {
159161
});
160162
}
161163

164+
void
165+
setup_libdisplaydevice_logging(int min_log_level) {
166+
constexpr int min_level { static_cast<int>(display_device::Logger::LogLevel::verbose) };
167+
constexpr int max_level { static_cast<int>(display_device::Logger::LogLevel::fatal) };
168+
const auto log_level { static_cast<display_device::Logger::LogLevel>(std::min(std::max(min_level, min_log_level), max_level)) };
169+
170+
display_device::Logger::get().setLogLevel(log_level);
171+
display_device::Logger::get().setCustomCallback([](const display_device::Logger::LogLevel level, const std::string &message) {
172+
switch (level) {
173+
case display_device::Logger::LogLevel::verbose:
174+
BOOST_LOG(verbose) << message;
175+
break;
176+
case display_device::Logger::LogLevel::debug:
177+
BOOST_LOG(debug) << message;
178+
break;
179+
case display_device::Logger::LogLevel::info:
180+
BOOST_LOG(info) << message;
181+
break;
182+
case display_device::Logger::LogLevel::warning:
183+
BOOST_LOG(warning) << message;
184+
break;
185+
case display_device::Logger::LogLevel::error:
186+
BOOST_LOG(error) << message;
187+
break;
188+
case display_device::Logger::LogLevel::fatal:
189+
BOOST_LOG(fatal) << message;
190+
break;
191+
}
192+
});
193+
}
194+
162195
void
163196
log_flush() {
164197
if (sink) {

src/logging.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,13 @@ namespace logging {
6666
void
6767
setup_av_logging(int min_log_level);
6868

69+
/**
70+
* @brief Setup logging for libdisplaydevice.
71+
* @param min_log_level The log level.
72+
*/
73+
void
74+
setup_libdisplaydevice_logging(int min_log_level);
75+
6976
/**
7077
* @brief Flush the log.
7178
* @examples

0 commit comments

Comments
 (0)