Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add new API to modify display devices for Windows #2582

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .github/workflows/CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1067,7 +1067,6 @@ jobs:
mingw-w64-ucrt-x86_64-cppwinrt \
mingw-w64-ucrt-x86_64-graphviz \
mingw-w64-ucrt-x86_64-miniupnpc \
mingw-w64-ucrt-x86_64-nlohmann-json \
mingw-w64-ucrt-x86_64-nodejs \
mingw-w64-ucrt-x86_64-nsis \
mingw-w64-ucrt-x86_64-onevpl \
Expand Down
4 changes: 4 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@
path = third-party/nanors
url = https://github.com/sleepybishop/nanors.git
branch = master
[submodule "third-party/nlohmann_json"]
path = third-party/nlohmann_json
url = https://github.com/nlohmann/json
branch = master
[submodule "third-party/nv-codec-headers"]
path = third-party/nv-codec-headers
url = https://github.com/FFmpeg/nv-codec-headers
Expand Down
10 changes: 10 additions & 0 deletions cmake/compile_definitions/common.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,15 @@ set(SUNSHINE_TARGET_FILES
"${CMAKE_SOURCE_DIR}/third-party/moonlight-common-c/src/RtspParser.c"
"${CMAKE_SOURCE_DIR}/third-party/moonlight-common-c/src/Video.h"
"${CMAKE_SOURCE_DIR}/third-party/tray/src/tray.h"
"${CMAKE_SOURCE_DIR}/src/display_device/display_device.h"
"${CMAKE_SOURCE_DIR}/src/display_device/parsed_config.cpp"
"${CMAKE_SOURCE_DIR}/src/display_device/parsed_config.h"
"${CMAKE_SOURCE_DIR}/src/display_device/session.cpp"
"${CMAKE_SOURCE_DIR}/src/display_device/session.h"
"${CMAKE_SOURCE_DIR}/src/display_device/settings.cpp"
"${CMAKE_SOURCE_DIR}/src/display_device/settings.h"
"${CMAKE_SOURCE_DIR}/src/display_device/to_string.cpp"
"${CMAKE_SOURCE_DIR}/src/display_device/to_string.h"
"${CMAKE_SOURCE_DIR}/src/upnp.cpp"
"${CMAKE_SOURCE_DIR}/src/upnp.h"
"${CMAKE_SOURCE_DIR}/src/cbs.cpp"
Expand Down Expand Up @@ -137,4 +146,5 @@ list(APPEND SUNSHINE_EXTERNAL_LIBRARIES
${FFMPEG_LIBRARIES}
${Boost_LIBRARIES}
${OPENSSL_LIBRARIES}
${JSON_LIBRARIES}
${PLATFORM_LIBRARIES})
1 change: 1 addition & 0 deletions cmake/compile_definitions/linux.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,7 @@ list(APPEND PLATFORM_TARGET_FILES
"${CMAKE_SOURCE_DIR}/src/platform/linux/misc.h"
"${CMAKE_SOURCE_DIR}/src/platform/linux/misc.cpp"
"${CMAKE_SOURCE_DIR}/src/platform/linux/audio.cpp"
"${CMAKE_SOURCE_DIR}/src/platform/linux/display_device.cpp"
"${CMAKE_SOURCE_DIR}/third-party/glad/src/egl.c"
"${CMAKE_SOURCE_DIR}/third-party/glad/src/gl.c"
"${CMAKE_SOURCE_DIR}/third-party/glad/include/EGL/eglplatform.h"
Expand Down
1 change: 1 addition & 0 deletions cmake/compile_definitions/macos.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ set(PLATFORM_TARGET_FILES
"${CMAKE_SOURCE_DIR}/src/platform/macos/av_video.h"
"${CMAKE_SOURCE_DIR}/src/platform/macos/av_video.m"
"${CMAKE_SOURCE_DIR}/src/platform/macos/display.mm"
"${CMAKE_SOURCE_DIR}/src/platform/macos/display_device.cpp"
"${CMAKE_SOURCE_DIR}/src/platform/macos/input.cpp"
"${CMAKE_SOURCE_DIR}/src/platform/macos/microphone.mm"
"${CMAKE_SOURCE_DIR}/src/platform/macos/misc.mm"
Expand Down
10 changes: 9 additions & 1 deletion cmake/compile_definitions/windows.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,15 @@ set(PLATFORM_TARGET_FILES
"${CMAKE_SOURCE_DIR}/src/platform/windows/display_ram.cpp"
"${CMAKE_SOURCE_DIR}/src/platform/windows/display_wgc.cpp"
"${CMAKE_SOURCE_DIR}/src/platform/windows/audio.cpp"
"${CMAKE_SOURCE_DIR}/src/platform/windows/display_device/device_hdr_states.cpp"
"${CMAKE_SOURCE_DIR}/src/platform/windows/display_device/device_modes.cpp"
"${CMAKE_SOURCE_DIR}/src/platform/windows/display_device/device_topology.cpp"
"${CMAKE_SOURCE_DIR}/src/platform/windows/display_device/general_functions.cpp"
"${CMAKE_SOURCE_DIR}/src/platform/windows/display_device/settings_topology.cpp"
"${CMAKE_SOURCE_DIR}/src/platform/windows/display_device/settings_topology.h"
"${CMAKE_SOURCE_DIR}/src/platform/windows/display_device/settings.cpp"
"${CMAKE_SOURCE_DIR}/src/platform/windows/display_device/windows_utils.h"
"${CMAKE_SOURCE_DIR}/src/platform/windows/display_device/windows_utils.cpp"
"${CMAKE_SOURCE_DIR}/third-party/ViGEmClient/src/ViGEmClient.cpp"
"${CMAKE_SOURCE_DIR}/third-party/ViGEmClient/include/ViGEm/Client.h"
"${CMAKE_SOURCE_DIR}/third-party/ViGEmClient/include/ViGEm/Common.h"
Expand Down Expand Up @@ -79,7 +88,6 @@ list(PREPEND PLATFORM_LIBRARIES
avrt
iphlpapi
shlwapi
PkgConfig::NLOHMANN_JSON
${CURL_STATIC_LIBRARIES})

if(SUNSHINE_ENABLE_TRAY)
Expand Down
9 changes: 9 additions & 0 deletions cmake/dependencies/common.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,15 @@ pkg_check_modules(CURL REQUIRED libcurl)
pkg_check_modules(MINIUPNP miniupnpc REQUIRED)
include_directories(SYSTEM ${MINIUPNP_INCLUDE_DIRS})

# nlohmann_json
if(SUNSHINE_SYSTEM_NLOHMANN_JSON)
pkg_check_modules(NLOHMANN_JSON nlohmann_json>=3.9.0 REQUIRED IMPORTED_TARGET)
set(JSON_LIBRARIES PkgConfig::NLOHMANN_JSON)
else()
add_subdirectory("${CMAKE_SOURCE_DIR}/third-party/nlohmann_json")
set(JSON_LIBRARIES nlohmann_json::nlohmann_json)
endif()

# ffmpeg pre-compiled binaries
if(NOT DEFINED FFMPEG_PREPARED_BINARIES)
if(WIN32)
Expand Down
3 changes: 0 additions & 3 deletions cmake/dependencies/windows.cmake
Original file line number Diff line number Diff line change
@@ -1,4 +1 @@
# windows specific dependencies

# nlohmann_json
pkg_check_modules(NLOHMANN_JSON nlohmann_json REQUIRED IMPORTED_TARGET)
1 change: 1 addition & 0 deletions cmake/prep/options.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ option(SUNSHINE_CONFIGURE_ONLY "Configure special files only, then exit." OFF)
option(SUNSHINE_ENABLE_TRAY "Enable system tray icon. This option will be ignored on macOS." ON)
option(SUNSHINE_REQUIRE_TRAY "Require system tray icon. Fail the build if tray requirements are not met." ON)

option(SUNSHINE_SYSTEM_NLOHMANN_JSON "Use system installation of nlohmann_json rather than the submodule." OFF)
option(SUNSHINE_SYSTEM_WAYLAND_PROTOCOLS "Use system installation of wayland-protocols rather than the submodule." OFF)

if(APPLE)
Expand Down
34 changes: 30 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,35 @@ 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 display devices:

tools\dxgi-info.exe
.. code-block:: text

DEVICE ID: {de9bb7e2-186e-505b-9e93-f48793333810}
DISPLAY NAME: \\.\DISPLAY1
FRIENDLY NAME: ROG PG279Q
DEVICE STATE: PRIMARY
HDR STATE: UNKNOWN
-----------------------
DEVICE ID: {3bd008cd-0465-547c-8da5-c28749c041e6}
DISPLAY NAME: NOT AVAILABLE
FRIENDLY NAME: IDD HDR
DEVICE STATE: INACTIVE
HDR STATE: UNKNOWN
-----------------------
DEVICE ID: {77f67f3e-754f-5d31-af64-ee037e18100a}
DISPLAY NAME: NOT AVAILABLE
FRIENDLY NAME: SunshineHDR
DEVICE STATE: INACTIVE
HDR STATE: UNKNOWN
-----------------------
DEVICE ID: {bc172e6d-86eb-5851-aeca-56525ed716e9}
DISPLAY NAME: NOT AVAILABLE
FRIENDLY NAME: ROG PG279Q
DEVICE STATE: INACTIVE
HDR STATE: UNKNOWN

You need to use the ``DEVICE ID`` value.

**Default**
Sunshine will select the default display.
Expand All @@ -637,7 +663,7 @@ keybindings
**Windows**
.. code-block:: text

output_name = \\.\DISPLAY1
output_name = {de9bb7e2-186e-505b-9e93-f48793333810}

`resolutions <https://localhost:47990/config/#resolutions>`__
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down
1 change: 0 additions & 1 deletion docs/source/building/windows.rst
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ Install dependencies:
mingw-w64-ucrt-x86_64-curl \
mingw-w64-ucrt-x86_64-graphviz \
mingw-w64-ucrt-x86_64-miniupnpc \
mingw-w64-ucrt-x86_64-nlohmann-json \
mingw-w64-ucrt-x86_64-nodejs \
mingw-w64-ucrt-x86_64-nsis \
mingw-w64-ucrt-x86_64-onevpl \
Expand Down
20 changes: 7 additions & 13 deletions src/audio.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,6 @@ namespace audio {
using opus_t = util::safe_ptr<OpusMSEncoder, opus_multistream_encoder_destroy>;
using sample_queue_t = std::shared_ptr<safe::queue_t<std::vector<float>>>;

struct audio_ctx_t {
// We want to change the sink for the first stream only
std::unique_ptr<std::atomic_bool> sink_flag;

std::unique_ptr<platf::audio_control_t> control;

bool restore_sink;
platf::sink_t sink;
};

static int
start_audio_control(audio_ctx_t &ctx);
static void
Expand Down Expand Up @@ -95,8 +85,6 @@ namespace audio {
},
};

auto control_shared = safe::make_shared<audio_ctx_t>(start_audio_control, stop_audio_control);

void
encodeThread(sample_queue_t samples, config_t config, void *channel_data) {
auto packets = mail::man->queue<packet_t>(mail::audio_packets);
Expand Down Expand Up @@ -149,7 +137,7 @@ namespace audio {
apply_surround_params(stream, config.customStreamParams);
}

auto ref = control_shared.ref();
auto ref = get_audio_ctx_ref();
if (!ref) {
return;
}
Expand Down Expand Up @@ -255,6 +243,12 @@ namespace audio {
}
}

audio_ctx_ref_t
get_audio_ctx_ref() {
static auto control_shared { safe::make_shared<audio_ctx_t>(start_audio_control, stop_audio_control) };
return control_shared.ref();
}

int
map_stream(int channels, bool quality) {
int shift = quality ? 1 : 0;
Expand Down
29 changes: 29 additions & 0 deletions src/audio.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,11 @@
*/
#pragma once

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

namespace audio {
enum stream_config_e : int {
STEREO, ///< Stereo
Expand Down Expand Up @@ -52,8 +55,34 @@ namespace audio {
std::bitset<MAX_FLAGS> flags;
};

struct audio_ctx_t {
// We want to change the sink for the first stream only
std::unique_ptr<std::atomic_bool> sink_flag;

std::unique_ptr<platf::audio_control_t> control;

bool restore_sink;
platf::sink_t sink;
};

using buffer_t = util::buffer_t<std::uint8_t>;
using packet_t = std::pair<void *, buffer_t>;
using audio_ctx_ref_t = safe::shared_t<audio::audio_ctx_t>::ptr_t;

void
capture(safe::mail_t mail, config_t config, void *channel_data);

/**
* @brief Get the reference to the audio context.
* @returns A shared pointer reference to audio context.
* @note Aside from the configuration purposes, it can be used to extend the
* audio sink lifetime to capture sink earlier and restore it later.
*
* EXAMPLES:
* ```cpp
* audio_ctx_ref_t audio = get_audio_ctx_ref()
* ```
*/
audio_ctx_ref_t
get_audio_ctx_ref();
} // namespace audio
53 changes: 52 additions & 1 deletion src/config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include "rtsp.h"
#include "utility.h"

#include "display_device/parsed_config.h"
#include "platform/common.h"

#ifdef _WIN32
Expand Down Expand Up @@ -377,7 +378,15 @@
{}, // capture
{}, // encoder
{}, // adapter_name

{}, // output_name
(int) display_device::parsed_config_t::device_prep_e::no_operation, // display_device_prep
(int) display_device::parsed_config_t::resolution_change_e::automatic, // resolution_change
{}, // manual_resolution
(int) display_device::parsed_config_t::refresh_rate_change_e::automatic, // refresh_rate_change
{}, // manual_refresh_rate
(int) display_device::parsed_config_t::hdr_prep_e::automatic, // hdr_prep
{} // display_mode_remapping
};

audio_t audio {
Expand Down Expand Up @@ -829,6 +838,40 @@
}
}

void
list_display_mode_remapping_f(std::unordered_map<std::string, std::string> &vars, const std::string &name, std::vector<video_t::display_mode_remapping_t> &input) {
std::string string;

Check warning on line 843 in src/config.cpp

View check run for this annotation

Codecov / codecov/patch

src/config.cpp#L842-L843

Added lines #L842 - L843 were not covered by tests
string_f(vars, name, string);

std::stringstream jsonStream;

// check if string is empty, i.e. when the value doesn't exist in the config file
if (string.empty()) {
return;
}

// We need to add a wrapping object to make it valid JSON, otherwise ptree cannot parse it.
jsonStream << "{\"display_mode_remapping\":" << string << "}";

boost::property_tree::ptree jsonTree;
boost::property_tree::read_json(jsonStream, jsonTree);

for (auto &[_, entry] : jsonTree.get_child("display_mode_remapping"s)) {
auto type = entry.get_optional<std::string>("type"s);
auto received_resolution = entry.get_optional<std::string>("received_resolution"s);
auto received_fps = entry.get_optional<std::string>("received_fps"s);
auto final_resolution = entry.get_optional<std::string>("final_resolution"s);
auto final_refresh_rate = entry.get_optional<std::string>("final_refresh_rate"s);

input.push_back(video_t::display_mode_remapping_t {
type.value_or(""),
received_resolution.value_or(""),
received_fps.value_or(""),
final_resolution.value_or(""),
final_refresh_rate.value_or("") });
}
}

void
list_prep_cmd_f(std::unordered_map<std::string, std::string> &vars, const std::string &name, std::vector<prep_cmd_t> &input) {
std::string string;
Expand Down Expand Up @@ -961,6 +1004,7 @@
}

int_f(vars, "qp", video.qp);
int_between_f(vars, "min_fps_factor", video.min_fps_factor, { 1, 3 });
int_f(vars, "min_threads", video.min_threads);
int_between_f(vars, "hevc_mode", video.hevc_mode, { 0, 3 });
int_between_f(vars, "av1_mode", video.av1_mode, { 0, 3 });
Expand Down Expand Up @@ -1030,8 +1074,15 @@
string_f(vars, "capture", video.capture);
string_f(vars, "encoder", video.encoder);
string_f(vars, "adapter_name", video.adapter_name);

string_f(vars, "output_name", video.output_name);
int_between_f(vars, "min_fps_factor", video.min_fps_factor, { 1, 3 });
int_f(vars, "display_device_prep", video.display_device_prep, display_device::parsed_config_t::device_prep_from_view);
int_f(vars, "resolution_change", video.resolution_change, display_device::parsed_config_t::resolution_change_from_view);
string_f(vars, "manual_resolution", video.manual_resolution);
list_display_mode_remapping_f(vars, "display_mode_remapping", video.display_mode_remapping);
int_f(vars, "refresh_rate_change", video.refresh_rate_change, display_device::parsed_config_t::refresh_rate_change_from_view);
string_f(vars, "manual_refresh_rate", video.manual_refresh_rate);
int_f(vars, "hdr_prep", video.hdr_prep, display_device::parsed_config_t::hdr_prep_from_view);

path_f(vars, "pkey", nvhttp.pkey);
path_f(vars, "cert", nvhttp.cert);
Expand Down
16 changes: 16 additions & 0 deletions src/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,23 @@ namespace config {
std::string capture;
std::string encoder;
std::string adapter_name;

struct display_mode_remapping_t {
std::string type;
std::string received_resolution;
std::string received_fps;
std::string final_resolution;
std::string final_refresh_rate;
};

std::string output_name;
int display_device_prep;
int resolution_change;
std::string manual_resolution;
int refresh_rate_change;
std::string manual_refresh_rate;
int hdr_prep;
std::vector<display_mode_remapping_t> display_mode_remapping;
};

struct audio_t {
Expand Down
Loading
Loading