1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
|
{
me,
lib,
pkgs,
auxiliaryPkgs,
...
}:
let
inherit (lib)
substring
toUpper
getExe
;
# todo: move this to a utils package
capitalize = str: toUpper (substring 0 1 str) + substring 1 (-1) str;
user = "mel";
# per machine sunshine settings
perMachine = {
# wolfram has an arc b570 gpu optimized for transcoding,
# and is the primary streaming machine
wolfram = {
adapter_name = "/dev/dri/renderD128"; # primary card should be located here
encoder = "vaapi"; # or "qsv" is quicksync is better supported
av1_mode = 2;
};
# bismuth has a radeon rx 9070 xt, and is only
# used when streaming from wolfram is impossible,
# as it's my personal desktop machine.
bismuth = {
adapter_name = "/dev/dri/renderD128"; # primary card should be located here
encoder = "amdvce";
av1_mode = 0;
hevc_mode = 2;
};
};
in
{
services.sunshine = {
enable = true;
autoStart = true;
capSysAdmin = true;
openFirewall = true;
settings = {
sunshine_name = capitalize me.name;
# no need for encryption since we are going through a secure network anyway
lan_encryption_mode = 0;
wan_encryption_mode = 0;
origin_web_ui_allowed = "wan"; # allow access everywhere
gamepad = "auto"; # to support ds5 and steam deck controllers
}
// perMachine.${me.name};
applications = {
env = {
# give sunshine access to binaries (we can install stuff into .local/bin if we want)
PATH = "$(PATH):/run/current-system/sw/bin:/etc/profiles/per-user/${user}/bin:$(HOME)/.local/bin";
};
apps =
let
command =
name: cmd:
getExe (
pkgs.writeShellApplication {
inherit name;
runtimeInputs = with pkgs; [
steam
util-linux
];
text = "sudo -u ${user} ${cmd}";
}
);
in
[
# moondeck will call this app when connecting via moonlight, automatically
{
name = "MoonDeckStream";
cmd = "${auxiliaryPkgs.moondeck-buddy}/bin/MoonDeckStream";
image-path = "${auxiliaryPkgs.moondeck-buddy}/share/icons/hicolor/256x256/apps/moondeckbuddy.png";
exclude-global-prep-cmd = "false";
elevated = "false";
}
# other applications, called manually
{
name = "Desktop";
image-path = "desktop.png";
# empty commands will always simply open desktop
}
{
name = "Steam";
image-path = "steam.png";
detached = [ (command "sunshine-open-steam-bp" "steam steam://open/bigpicture") ];
prep-cmd = [
{
do = "";
undo = command "sunshine-close-steam-bp" "steam steam://close/bigpicture"; # close up steam
}
];
# sunshine can't track the steam startup properly, so don't.
auto-detach = "true";
wait-all = "true";
exit-timeout = "5";
}
];
};
};
# run the buddy app for the moondeck for a nicer integration of sunshine/moonlight
# when using a steam deck!
systemd.user.services.moondeck-buddy = {
description = "MoonDeck Buddy";
wantedBy = [ "graphical-session.target" ];
partOf = [ "graphical-session.target" ];
after = [
"graphical-session.target"
"network-online.target"
];
serviceConfig = {
ExecStart = "${getExe auxiliaryPkgs.moondeck-buddy}";
# try to stay alive even if something moondeck-buddy depends on,
# like steam, crashes.
Restart = "on-failure";
RestartSec = "5s";
Environment = "QT_QPA_PLATFORM=wayland";
};
};
networking.firewall.allowedTCPPorts = [ 59999 ]; # port for moondeck-buddy
}
|