Skip to content

Commit 0112fa9

Browse files
FrogTheFrogReenigneArcher
authored andcommitted
feat: Configure display device based on user config
1 parent df0bc3f commit 0112fa9

File tree

22 files changed

+1690
-95
lines changed

22 files changed

+1690
-95
lines changed

docs/configuration.md

Lines changed: 241 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -958,6 +958,247 @@ editing the `conf` file in a text editor. Use the examples as reference.
958958
</tr>
959959
</table>
960960

961+
### dd_configuration_option
962+
963+
<table>
964+
<tr>
965+
<td>Description</td>
966+
<td colspan="2">
967+
Perform mandatory verification and additional configuration for the display device.
968+
@note{Applies to Windows only.}
969+
</td>
970+
</tr>
971+
<tr>
972+
<td>Default</td>
973+
<td colspan="2">@code{}verify_only@endcode</td>
974+
</tr>
975+
<tr>
976+
<td>Example</td>
977+
<td colspan="2">@code{}
978+
dd_configuration_option = ensure_only_display
979+
@endcode</td>
980+
</tr>
981+
<tr>
982+
<td rowspan="5">Choices</td>
983+
<td>disabled</td>
984+
<td>Perform no additional configuration (disables all `dd_` configuration options).</td>
985+
</tr>
986+
<tr>
987+
<td>verify_only</td>
988+
<td>Verify that display is active only (this is a mandatory step without any extra steps to verify display state).</td>
989+
</tr>
990+
<tr>
991+
<td>ensure_active</td>
992+
<td>Activate the display if it's currently inactive.</td>
993+
</tr>
994+
<tr>
995+
<td>ensure_primary</td>
996+
<td>Activate the display if it's currently inactive and make it primary.</td>
997+
</tr>
998+
<tr>
999+
<td>ensure_only_display</td>
1000+
<td>Activate the display if it's currently inactive and disable all others.</td>
1001+
</tr>
1002+
</table>
1003+
1004+
### dd_resolution_option
1005+
1006+
<table>
1007+
<tr>
1008+
<td>Description</td>
1009+
<td colspan="2">
1010+
Perform additional resolution configuration for the display device.
1011+
@note{"Optimize game settings" must be enabled in Moonlight for this option to work.}
1012+
@note{Applies to Windows only.}
1013+
</td>
1014+
</tr>
1015+
<tr>
1016+
<td>Default</td>
1017+
<td colspan="2">@code{}auto@endcode</td>
1018+
</tr>
1019+
<tr>
1020+
<td>Example</td>
1021+
<td colspan="2">@code{}
1022+
dd_resolution_option = manual
1023+
@endcode</td>
1024+
</tr>
1025+
<tr>
1026+
<td rowspan="3">Choices</td>
1027+
<td>disabled</td>
1028+
<td>Perform no additional configuration.</td>
1029+
</tr>
1030+
<tr>
1031+
<td>auto</td>
1032+
<td>Change resolution to the requested resolution from the client.</td>
1033+
</tr>
1034+
<tr>
1035+
<td>manual</td>
1036+
<td>Change resolution to the user specified one (set via [dd_manual_resolution](#dd_manual_resolution)).</td>
1037+
</tr>
1038+
</table>
1039+
1040+
### dd_manual_resolution
1041+
1042+
<table>
1043+
<tr>
1044+
<td>Description</td>
1045+
<td colspan="2">
1046+
Specify manual resolution to be used.
1047+
@note{[dd_resolution_option](#dd_resolution_option) must be set to `manual`}
1048+
@note{Applies to Windows only.}
1049+
</td>
1050+
</tr>
1051+
<tr>
1052+
<td>Default</td>
1053+
<td colspan="2">n/a</td>
1054+
</tr>
1055+
<tr>
1056+
<td>Example</td>
1057+
<td colspan="2">@code{}
1058+
dd_manual_resolution = 1920x1080
1059+
@endcode</td>
1060+
</tr>
1061+
</table>
1062+
1063+
### dd_refresh_rate_option
1064+
1065+
<table>
1066+
<tr>
1067+
<td>Description</td>
1068+
<td colspan="2">
1069+
Perform additional refresh rate configuration for the display device.
1070+
@note{Applies to Windows only.}
1071+
</td>
1072+
</tr>
1073+
<tr>
1074+
<td>Default</td>
1075+
<td colspan="2">@code{}auto@endcode</td>
1076+
</tr>
1077+
<tr>
1078+
<td>Example</td>
1079+
<td colspan="2">@code{}
1080+
dd_refresh_rate_option = manual
1081+
@endcode</td>
1082+
</tr>
1083+
<tr>
1084+
<td rowspan="3">Choices</td>
1085+
<td>disabled</td>
1086+
<td>Perform no additional configuration.</td>
1087+
</tr>
1088+
<tr>
1089+
<td>auto</td>
1090+
<td>Change refresh rate to the requested FPS value from the client.</td>
1091+
</tr>
1092+
<tr>
1093+
<td>manual</td>
1094+
<td>Change refresh rate to the user specified one (set via [dd_manual_refresh_rate](#dd_manual_refresh_rate)).</td>
1095+
</tr>
1096+
</table>
1097+
1098+
### dd_manual_refresh_rate
1099+
1100+
<table>
1101+
<tr>
1102+
<td>Description</td>
1103+
<td colspan="2">
1104+
Specify manual refresh rate to be used.
1105+
@note{[dd_refresh_rate_option](#dd_refresh_rate_option) must be set to `manual`}
1106+
@note{Applies to Windows only.}
1107+
</td>
1108+
</tr>
1109+
<tr>
1110+
<td>Default</td>
1111+
<td colspan="2">n/a</td>
1112+
</tr>
1113+
<tr>
1114+
<td>Example</td>
1115+
<td colspan="2">@code{}
1116+
dd_manual_resolution = 120
1117+
dd_manual_resolution = 59.95
1118+
@endcode</td>
1119+
</tr>
1120+
</table>
1121+
1122+
### dd_hdr_option
1123+
1124+
<table>
1125+
<tr>
1126+
<td>Description</td>
1127+
<td colspan="2">
1128+
Perform additional HDR configuration for the display device.
1129+
@note{Applies to Windows only.}
1130+
</td>
1131+
</tr>
1132+
<tr>
1133+
<td>Default</td>
1134+
<td colspan="2">@code{}auto@endcode</td>
1135+
</tr>
1136+
<tr>
1137+
<td>Example</td>
1138+
<td colspan="2">@code{}
1139+
dd_hdr_option = disabled
1140+
@endcode</td>
1141+
</tr>
1142+
<tr>
1143+
<td rowspan="2">Choices</td>
1144+
<td>disabled</td>
1145+
<td>Perform no additional configuration.</td>
1146+
</tr>
1147+
<tr>
1148+
<td>auto</td>
1149+
<td>Change HDR to the requested state from the client if the display supports it.</td>
1150+
</tr>
1151+
</table>
1152+
1153+
### dd_wa_hdr_toggle
1154+
1155+
<table>
1156+
<tr>
1157+
<td>Description</td>
1158+
<td colspan="2">
1159+
When using virtual display device as for streaming, it might display incorrect (high-contrast) color.
1160+
With this option enabled, Sunshine will try to mitigate this issue.
1161+
@note{This option works independently of [dd_hdr_option](#dd_hdr_option)}
1162+
@note{Applies to Windows only.}
1163+
</td>
1164+
</tr>
1165+
<tr>
1166+
<td>Default</td>
1167+
<td colspan="2">@code{}
1168+
disabled
1169+
@endcode</td>
1170+
</tr>
1171+
<tr>
1172+
<td>Example</td>
1173+
<td colspan="2">@code{}
1174+
dd_wa_hdr_toggle = enabled
1175+
@endcode</td>
1176+
</tr>
1177+
</table>
1178+
1179+
### dd_config_revert_delay
1180+
1181+
<table>
1182+
<tr>
1183+
<td>Description</td>
1184+
<td colspan="2">
1185+
Additional delay in milliseconds to wait before reverting configuration when the app has been closed or the last session terminated.
1186+
Main purpose is to provide a smoother transition when quickly switching between apps.
1187+
@note{Applies to Windows only.}
1188+
</td>
1189+
</tr>
1190+
<tr>
1191+
<td>Default</td>
1192+
<td colspan="2">@code{}3000@endcode</td>
1193+
</tr>
1194+
<tr>
1195+
<td>Example</td>
1196+
<td colspan="2">@code{}
1197+
dd_config_revert_delay = 1500
1198+
@endcode</td>
1199+
</tr>
1200+
</table>
1201+
9611202
### min_fps_factor
9621203

9631204
<table>

src/audio.cpp

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -20,16 +20,6 @@ namespace audio {
2020
using opus_t = util::safe_ptr<OpusMSEncoder, opus_multistream_encoder_destroy>;
2121
using sample_queue_t = std::shared_ptr<safe::queue_t<std::vector<float>>>;
2222

23-
struct audio_ctx_t {
24-
// We want to change the sink for the first stream only
25-
std::unique_ptr<std::atomic_bool> sink_flag;
26-
27-
std::unique_ptr<platf::audio_control_t> control;
28-
29-
bool restore_sink;
30-
platf::sink_t sink;
31-
};
32-
3323
static int
3424
start_audio_control(audio_ctx_t &ctx);
3525
static void
@@ -95,8 +85,6 @@ namespace audio {
9585
},
9686
};
9787

98-
auto control_shared = safe::make_shared<audio_ctx_t>(start_audio_control, stop_audio_control);
99-
10088
void
10189
encodeThread(sample_queue_t samples, config_t config, void *channel_data) {
10290
auto packets = mail::man->queue<packet_t>(mail::audio_packets);
@@ -149,7 +137,7 @@ namespace audio {
149137
apply_surround_params(stream, config.customStreamParams);
150138
}
151139

152-
auto ref = control_shared.ref();
140+
auto ref = get_audio_ctx_ref();
153141
if (!ref) {
154142
return;
155143
}
@@ -255,6 +243,26 @@ namespace audio {
255243
}
256244
}
257245

246+
audio_ctx_ref_t
247+
get_audio_ctx_ref() {
248+
static auto control_shared { safe::make_shared<audio_ctx_t>(start_audio_control, stop_audio_control) };
249+
return control_shared.ref();
250+
}
251+
252+
bool
253+
is_audio_ctx_sink_available(const audio_ctx_t &ctx) {
254+
if (!ctx.control) {
255+
return false;
256+
}
257+
258+
const std::string &sink = ctx.sink.host.empty() ? config::audio.sink : ctx.sink.host;
259+
if (sink.empty()) {
260+
return false;
261+
}
262+
263+
return ctx.control->is_sink_available(sink);
264+
}
265+
258266
int
259267
map_stream(int channels, bool quality) {
260268
int shift = quality ? 1 : 0;

src/audio.h

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
*/
55
#pragma once
66

7+
// local includes
8+
#include "platform/common.h"
79
#include "thread_safe.h"
810
#include "utility.h"
911

@@ -55,8 +57,50 @@ namespace audio {
5557
std::bitset<MAX_FLAGS> flags;
5658
};
5759

60+
struct audio_ctx_t {
61+
// We want to change the sink for the first stream only
62+
std::unique_ptr<std::atomic_bool> sink_flag;
63+
64+
std::unique_ptr<platf::audio_control_t> control;
65+
66+
bool restore_sink;
67+
platf::sink_t sink;
68+
};
69+
5870
using buffer_t = util::buffer_t<std::uint8_t>;
5971
using packet_t = std::pair<void *, buffer_t>;
72+
using audio_ctx_ref_t = safe::shared_t<audio_ctx_t>::ptr_t;
73+
6074
void
6175
capture(safe::mail_t mail, config_t config, void *channel_data);
76+
77+
/**
78+
* @brief Get the reference to the audio context.
79+
* @returns A shared pointer reference to audio context.
80+
* @note Aside from the configuration purposes, it can be used to extend the
81+
* audio sink lifetime to capture sink earlier and restore it later.
82+
*
83+
* @examples
84+
* audio_ctx_ref_t audio = get_audio_ctx_ref()
85+
* @examples_end
86+
*/
87+
audio_ctx_ref_t
88+
get_audio_ctx_ref();
89+
90+
/**
91+
* @brief Check if the audio sink held by audio context is available.
92+
* @returns True if available (and can probably be restored), false otherwise.
93+
* @note Useful for delaying the release of audio context shared pointer (which
94+
* tries to restore original sink).
95+
*
96+
* @examples
97+
* audio_ctx_ref_t audio = get_audio_ctx_ref()
98+
* if (audio.get()) {
99+
* return is_audio_ctx_sink_available(*audio.get());
100+
* }
101+
* return false;
102+
* @examples_end
103+
*/
104+
bool
105+
is_audio_ctx_sink_available(const audio_ctx_t &ctx);
62106
} // namespace audio

0 commit comments

Comments
 (0)