Sunshine v2025.118.151840
Self-hosted game stream host for Moonlight.
common.h
Go to the documentation of this file.
1
5#pragma once
6
7#include <bitset>
8#include <filesystem>
9#include <functional>
10#include <mutex>
11#include <string>
12
13#include <boost/core/noncopyable.hpp>
14#ifndef _WIN32
15 #include <boost/asio.hpp>
16 #include <boost/process.hpp>
17#endif
18
19#include "src/config.h"
20#include "src/logging.h"
21#include "src/thread_safe.h"
22#include "src/utility.h"
24
25extern "C" {
26#include <moonlight-common-c/src/Limelight.h>
27}
28
29using namespace std::literals;
30
31struct sockaddr;
32struct AVFrame;
33struct AVBufferRef;
34struct AVHWFramesContext;
35struct AVCodecContext;
36struct AVDictionary;
37
38#ifdef _WIN32
39// Forward declarations of boost classes to avoid having to include boost headers
40// here, which results in issues with Windows.h and WinSock2.h include order.
41namespace boost {
42 namespace asio {
43 namespace ip {
44 class address;
45 } // namespace ip
46 } // namespace asio
47 namespace filesystem {
48 class path;
49 }
50 namespace process::inline v1 {
51 class child;
52 class group;
53 template <typename Char>
56 } // namespace process::inline v1
57} // namespace boost
58#endif
59namespace video {
60 struct config_t;
61} // namespace video
62namespace nvenc {
63 class nvenc_base;
64}
65
66namespace platf {
67 // Limited by bits in activeGamepadMask
68 constexpr auto MAX_GAMEPADS = 16;
69
70 constexpr std::uint32_t DPAD_UP = 0x0001;
71 constexpr std::uint32_t DPAD_DOWN = 0x0002;
72 constexpr std::uint32_t DPAD_LEFT = 0x0004;
73 constexpr std::uint32_t DPAD_RIGHT = 0x0008;
74 constexpr std::uint32_t START = 0x0010;
75 constexpr std::uint32_t BACK = 0x0020;
76 constexpr std::uint32_t LEFT_STICK = 0x0040;
77 constexpr std::uint32_t RIGHT_STICK = 0x0080;
78 constexpr std::uint32_t LEFT_BUTTON = 0x0100;
79 constexpr std::uint32_t RIGHT_BUTTON = 0x0200;
80 constexpr std::uint32_t HOME = 0x0400;
81 constexpr std::uint32_t A = 0x1000;
82 constexpr std::uint32_t B = 0x2000;
83 constexpr std::uint32_t X = 0x4000;
84 constexpr std::uint32_t Y = 0x8000;
85 constexpr std::uint32_t PADDLE1 = 0x010000;
86 constexpr std::uint32_t PADDLE2 = 0x020000;
87 constexpr std::uint32_t PADDLE3 = 0x040000;
88 constexpr std::uint32_t PADDLE4 = 0x080000;
89 constexpr std::uint32_t TOUCHPAD_BUTTON = 0x100000;
90 constexpr std::uint32_t MISC_BUTTON = 0x200000;
91
93 std::string name;
94 bool is_enabled;
95 std::string reason_disabled;
96 };
97
104
107 make_rumble(std::uint16_t id, std::uint16_t lowfreq, std::uint16_t highfreq) {
109 msg.type = gamepad_feedback_e::rumble;
110 msg.id = id;
111 msg.data.rumble = { lowfreq, highfreq };
112 return msg;
113 }
114
116 make_rumble_triggers(std::uint16_t id, std::uint16_t left, std::uint16_t right) {
118 msg.type = gamepad_feedback_e::rumble_triggers;
119 msg.id = id;
120 msg.data.rumble_triggers = { left, right };
121 return msg;
122 }
123
125 make_motion_event_state(std::uint16_t id, std::uint8_t motion_type, std::uint16_t report_rate) {
127 msg.type = gamepad_feedback_e::set_motion_event_state;
128 msg.id = id;
129 msg.data.motion_event_state.motion_type = motion_type;
130 msg.data.motion_event_state.report_rate = report_rate;
131 return msg;
132 }
133
135 make_rgb_led(std::uint16_t id, std::uint8_t r, std::uint8_t g, std::uint8_t b) {
137 msg.type = gamepad_feedback_e::set_rgb_led;
138 msg.id = id;
139 msg.data.rgb_led = { r, g, b };
140 return msg;
141 }
142
144 std::uint16_t id;
145 union {
146 struct {
147 std::uint16_t lowfreq;
148 std::uint16_t highfreq;
149 } rumble;
150 struct {
151 std::uint16_t left_trigger;
152 std::uint16_t right_trigger;
153 } rumble_triggers;
154 struct {
155 std::uint16_t report_rate;
156 std::uint8_t motion_type;
157 } motion_event_state;
158 struct {
159 std::uint8_t r;
160 std::uint8_t g;
161 std::uint8_t b;
162 } rgb_led;
163 } data;
164 };
165
166 using feedback_queue_t = safe::mail_raw_t::queue_t<gamepad_feedback_msg_t>;
167
168 namespace speaker {
180
181 constexpr std::uint8_t map_stereo[] {
182 FRONT_LEFT, FRONT_RIGHT
183 };
184 constexpr std::uint8_t map_surround51[] {
185 FRONT_LEFT,
186 FRONT_RIGHT,
187 FRONT_CENTER,
188 LOW_FREQUENCY,
189 BACK_LEFT,
190 BACK_RIGHT,
191 };
192 constexpr std::uint8_t map_surround71[] {
197 BACK_LEFT,
199 SIDE_LEFT,
201 };
202 } // namespace speaker
203
204 enum class mem_type_e {
205 system,
206 vaapi,
207 dxgi,
208 cuda,
209 videotoolbox,
210 unknown
211 };
212
213 enum class pix_fmt_e {
214 yuv420p,
215 yuv420p10,
216 nv12,
217 p010,
218 ayuv,
219 yuv444p16,
220 y410,
221 unknown
222 };
223
224 inline std::string_view
225 from_pix_fmt(pix_fmt_e pix_fmt) {
226 using namespace std::literals;
227#define _CONVERT(x) \
228 case pix_fmt_e::x: \
229 return #x##sv
230 switch (pix_fmt) {
231 _CONVERT(yuv420p);
232 _CONVERT(yuv420p10);
233 _CONVERT(nv12);
234 _CONVERT(p010);
235 _CONVERT(ayuv);
236 _CONVERT(yuv444p16);
237 _CONVERT(y410);
238 _CONVERT(unknown);
239 }
240#undef _CONVERT
241
242 return "unknown"sv;
243 }
244
245 // Dimensions for touchscreen input
247 int offset_x, offset_y;
248 int width, height;
249 };
250
251 // These values must match Limelight-internal.h's SS_FF_* constants!
252 namespace platform_caps {
253 typedef uint32_t caps_t;
254
255 constexpr caps_t pen_touch = 0x01; // Pen and touch events
256 constexpr caps_t controller_touch = 0x02; // Controller touch events
257 }; // namespace platform_caps
258
260 std::uint32_t buttonFlags;
261 std::uint8_t lt;
262 std::uint8_t rt;
263 std::int16_t lsX;
264 std::int16_t lsY;
265 std::int16_t rsX;
266 std::int16_t rsY;
267 };
268
270 // The global index is used when looking up gamepads in the platform's
271 // gamepad array. It identifies gamepads uniquely among all clients.
272 int globalIndex;
273
274 // The client-relative index is the controller number as reported by the
275 // client. It must be used when communicating back to the client via
276 // the input feedback queue.
277 std::uint8_t clientRelativeIndex;
278 };
279
281 std::uint8_t type;
282 std::uint16_t capabilities;
283 std::uint32_t supportedButtons;
284 };
285
287 gamepad_id_t id;
288 std::uint8_t eventType;
289 std::uint32_t pointerId;
290 float x;
291 float y;
292 float pressure;
293 };
294
296 gamepad_id_t id;
297 std::uint8_t motionType;
298
299 // Accel: m/s^2
300 // Gyro: deg/s
301 float x;
302 float y;
303 float z;
304 };
305
307 gamepad_id_t id;
308 std::uint8_t state;
309 std::uint8_t percentage;
310 };
311
313 std::uint8_t eventType;
314 std::uint16_t rotation; // Degrees (0..360) or LI_ROT_UNKNOWN
315 std::uint32_t pointerId;
316 float x;
317 float y;
318 float pressureOrDistance; // Distance for hover and pressure for contact
319 float contactAreaMajor;
320 float contactAreaMinor;
321 };
322
323 struct pen_input_t {
324 std::uint8_t eventType;
325 std::uint8_t toolType;
326 std::uint8_t penButtons;
327 std::uint8_t tilt; // Degrees (0..90) or LI_TILT_UNKNOWN
328 std::uint16_t rotation; // Degrees (0..360) or LI_ROT_UNKNOWN
329 float x;
330 float y;
331 float pressureOrDistance; // Distance for hover and pressure for contact
332 float contactAreaMajor;
333 float contactAreaMinor;
334 };
335
336 class deinit_t {
337 public:
338 virtual ~deinit_t() = default;
339 };
340
341 struct img_t: std::enable_shared_from_this<img_t> {
342 public:
343 img_t() = default;
344
345 img_t(img_t &&) = delete;
346 img_t(const img_t &) = delete;
347 img_t &
348 operator=(img_t &&) = delete;
349 img_t &
350 operator=(const img_t &) = delete;
351
352 std::uint8_t *data {};
353 std::int32_t width {};
354 std::int32_t height {};
355 std::int32_t pixel_pitch {};
356 std::int32_t row_pitch {};
357
358 std::optional<std::chrono::steady_clock::time_point> frame_timestamp;
359
360 virtual ~img_t() = default;
361 };
362
363 struct sink_t {
364 // Play on host PC
365 std::string host;
366
367 // On macOS and Windows, it is not possible to create a virtual sink
368 // Therefore, it is optional
369 struct null_t {
370 std::string stereo;
371 std::string surround51;
372 std::string surround71;
373 };
374 std::optional<null_t> null;
375 };
376
378 virtual ~encode_device_t() = default;
379
380 virtual int
381 convert(platf::img_t &img) = 0;
382
384 };
385
387 void *data {};
388 AVFrame *frame {};
389
390 int
391 convert(platf::img_t &img) override {
392 return -1;
393 }
394
395 virtual void
396 apply_colorspace() {
397 }
398
403 virtual int
404 set_frame(AVFrame *frame, AVBufferRef *hw_frames_ctx) {
405 BOOST_LOG(error) << "Illegal call to hwdevice_t::set_frame(). Did you forget to override it?";
406 return -1;
407 };
408
413 virtual void
414 init_hwframes(AVHWFramesContext *frames) {};
415
420 virtual void
421 init_codec_options(AVCodecContext *ctx, AVDictionary **options) {};
422
427 virtual int
428 prepare_to_derive_context(int hw_device_type) {
429 return 0;
430 };
431 };
432
434 virtual bool
435 init_encoder(const video::config_t &client_config, const video::sunshine_colorspace_t &colorspace) = 0;
436
437 nvenc::nvenc_base *nvenc = nullptr;
438 };
439
440 enum class capture_e : int {
441 ok,
442 reinit,
443 timeout,
445 error
446 };
447
448 class display_t {
449 public:
457 using push_captured_image_cb_t = std::function<bool(std::shared_ptr<img_t> &&img, bool frame_captured)>;
458
466 using pull_free_image_cb_t = std::function<bool(std::shared_ptr<img_t> &img_out)>;
467
468 display_t() noexcept:
469 offset_x { 0 }, offset_y { 0 } {}
470
483 virtual capture_e
484 capture(const push_captured_image_cb_t &push_captured_image_cb, const pull_free_image_cb_t &pull_free_image_cb, bool *cursor) = 0;
485
486 virtual std::shared_ptr<img_t>
487 alloc_img() = 0;
488
489 virtual int
490 dummy_img(img_t *img) = 0;
491
492 virtual std::unique_ptr<avcodec_encode_device_t>
493 make_avcodec_encode_device(pix_fmt_e pix_fmt) {
494 return nullptr;
495 }
496
497 virtual std::unique_ptr<nvenc_encode_device_t>
498 make_nvenc_encode_device(pix_fmt_e pix_fmt) {
499 return nullptr;
500 }
501
502 virtual bool
503 is_hdr() {
504 return false;
505 }
506
507 virtual bool
508 get_hdr_metadata(SS_HDR_METADATA &metadata) {
509 std::memset(&metadata, 0, sizeof(metadata));
510 return false;
511 }
512
519 virtual bool
520 is_codec_supported(std::string_view name, const ::video::config_t &config) {
521 return true;
522 }
523
524 virtual ~display_t() = default;
525
526 // Offsets for when streaming a specific monitor. By default, they are 0.
527 int offset_x, offset_y;
528 int env_width, env_height;
529
530 int width, height;
531
532 protected:
533 // collect capture timing data (at loglevel debug)
534 logging::time_delta_periodic_logger sleep_overshoot_logger = { debug, "Frame capture sleep overshoot" };
535 };
536
537 class mic_t {
538 public:
539 virtual capture_e
540 sample(std::vector<float> &frame_buffer) = 0;
541
542 virtual ~mic_t() = default;
543 };
544
546 public:
547 virtual int
548 set_sink(const std::string &sink) = 0;
549
550 virtual std::unique_ptr<mic_t>
551 microphone(const std::uint8_t *mapping, int channels, std::uint32_t sample_rate, std::uint32_t frame_size) = 0;
552
558 virtual bool
559 is_sink_available(const std::string &sink) = 0;
560
561 virtual std::optional<sink_t>
562 sink_info() = 0;
563
564 virtual ~audio_control_t() = default;
565 };
566
567 void
568 freeInput(void *);
569
571
572 std::filesystem::path
573 appdata();
574
575 std::string
576 get_mac_address(const std::string_view &address);
577
578 std::string
579 from_sockaddr(const sockaddr *const);
580 std::pair<std::uint16_t, std::string>
581 from_sockaddr_ex(const sockaddr *const);
582
583 std::unique_ptr<audio_control_t>
584 audio_control();
585
594 std::shared_ptr<display_t>
595 display(mem_type_e hwdevice_type, const std::string &display_name, const video::config_t &config);
596
597 // A list of names of displays accepted as display_name with the mem_type_e
598 std::vector<std::string>
599 display_names(mem_type_e hwdevice_type);
600
605 bool
607
608 boost::process::v1::child
609 run_command(bool elevated, bool interactive, const std::string &cmd, boost::filesystem::path &working_dir, const boost::process::v1::environment &env, FILE *file, std::error_code &ec, boost::process::v1::group *group);
610
611 enum class thread_priority_e : int {
612 low,
613 normal,
614 high,
615 critical
616 };
617 void
618 adjust_thread_priority(thread_priority_e priority);
619
620 // Allow OS-specific actions to be taken to prepare for streaming
621 void
622 streaming_will_start();
623 void
624 streaming_will_stop();
625
626 void
627 restart();
628
635 int
636 set_env(const std::string &name, const std::string &value);
637
643 int
644 unset_env(const std::string &name);
645
647 const char *buffer;
648 size_t size;
649
650 // Constructors required for emplace_back() prior to C++20
651 buffer_descriptor_t(const char *buffer, size_t size):
652 buffer(buffer), size(size) {}
654 buffer(nullptr), size(0) {}
655 };
656
658 // Optional headers to be prepended to each packet
659 const char *headers;
660 size_t header_size;
661
662 // One or more data buffers to use for the payloads
663 //
664 // NB: Data buffers must be aligned to payload size!
665 std::vector<buffer_descriptor_t> &payload_buffers;
666 size_t payload_size;
667
668 // The offset (in header+payload message blocks) in the header and payload
669 // buffers to begin sending messages from
670 size_t block_offset;
671
672 // The number of header+payload message blocks to send
673 size_t block_count;
674
675 std::uintptr_t native_socket;
676 boost::asio::ip::address &target_address;
677 uint16_t target_port;
678 boost::asio::ip::address &source_address;
679
686 buffer_for_payload_offset(ptrdiff_t offset) {
687 for (const auto &desc : payload_buffers) {
688 if (offset < desc.size) {
689 return {
690 desc.buffer + offset,
691 desc.size - offset,
692 };
693 }
694 else {
695 offset -= desc.size;
696 }
697 }
698 return {};
699 }
700 };
701 bool
702 send_batch(batched_send_info_t &send_info);
703
704 struct send_info_t {
705 const char *header;
706 size_t header_size;
707 const char *payload;
708 size_t payload_size;
709
710 std::uintptr_t native_socket;
711 boost::asio::ip::address &target_address;
712 uint16_t target_port;
713 boost::asio::ip::address &source_address;
714 };
715 bool
716 send(send_info_t &send_info);
717
718 enum class qos_data_type_e : int {
719 audio,
720 video
721 };
722
731 std::unique_ptr<deinit_t>
732 enable_socket_qos(uintptr_t native_socket, boost::asio::ip::address &address, uint16_t port, qos_data_type_e data_type, bool dscp_tagging);
733
738 void
739 open_url(const std::string &url);
740
746 bool
747 request_process_group_exit(std::uintptr_t native_handle);
748
754 bool
755 process_group_running(std::uintptr_t native_handle);
756
757 input_t
758 input();
768 get_mouse_loc(input_t &input);
769 void
770 move_mouse(input_t &input, int deltaX, int deltaY);
771 void
772 abs_mouse(input_t &input, const touch_port_t &touch_port, float x, float y);
773 void
774 button_mouse(input_t &input, int button, bool release);
775 void
776 scroll(input_t &input, int distance);
777 void
778 hscroll(input_t &input, int distance);
779 void
780 keyboard_update(input_t &input, uint16_t modcode, bool release, uint8_t flags);
781 void
782 gamepad_update(input_t &input, int nr, const gamepad_state_t &gamepad_state);
783 void
784 unicode(input_t &input, char *utf8, int size);
785
786 typedef deinit_t client_input_t;
787
793 std::unique_ptr<client_input_t>
794 allocate_client_input_context(input_t &input);
795
802 void
803 touch_update(client_input_t *input, const touch_port_t &touch_port, const touch_input_t &touch);
804
811 void
812 pen_update(client_input_t *input, const touch_port_t &touch_port, const pen_input_t &pen);
813
819 void
820 gamepad_touch(input_t &input, const gamepad_touch_t &touch);
821
827 void
828 gamepad_motion(input_t &input, const gamepad_motion_t &motion);
829
835 void
836 gamepad_battery(input_t &input, const gamepad_battery_t &battery);
837
846 int
847 alloc_gamepad(input_t &input, const gamepad_id_t &id, const gamepad_arrival_t &metadata, feedback_queue_t feedback_queue);
848 void
849 free_gamepad(input_t &input, int nr);
850
855 platform_caps::caps_t
856 get_capabilities();
857
858#define SERVICE_NAME "Sunshine"
859#define SERVICE_TYPE "_nvstream._tcp"
860
861 namespace publish {
862 [[nodiscard]] std::unique_ptr<deinit_t>
863 start();
864 }
865
866 [[nodiscard]] std::unique_ptr<deinit_t>
867 init();
868
873 std::string
875
882 std::vector<supported_gamepad_t> &
883 supported_gamepads(input_t *input);
884
885 struct high_precision_timer: private boost::noncopyable {
886 virtual ~high_precision_timer() = default;
887
892 virtual void
893 sleep_for(const std::chrono::nanoseconds &duration) = 0;
894
899 virtual
900 operator bool() = 0;
901 };
902
907 std::unique_ptr<high_precision_timer>
909
910} // namespace platf
Definition common.h:54
A helper class for tracking and logging short time intervals across a period of time.
Definition logging.h:176
Abstract platform-agnostic base of standalone NVENC encoder. Derived classes perform platform-specifi...
Definition nvenc_base.h:25
Definition common.h:545
virtual bool is_sink_available(const std::string &sink)=0
Check if the audio sink is available in the system.
Definition common.h:336
Definition common.h:448
virtual bool is_codec_supported(std::string_view name, const ::video::config_t &config)
Check that a given codec is supported by the display device.
Definition common.h:520
std::function< bool(std::shared_ptr< img_t > &&img, bool frame_captured)> push_captured_image_cb_t
Callback for when a new image is ready. When display has a new image ready or a timeout occurs,...
Definition common.h:457
std::function< bool(std::shared_ptr< img_t > &img_out)> pull_free_image_cb_t
Get free image from pool. Calls must be synchronized. Blocks until there is free image in the pool or...
Definition common.h:466
virtual capture_e capture(const push_captured_image_cb_t &push_captured_image_cb, const pull_free_image_cb_t &pull_free_image_cb, bool *cursor)=0
Capture a frame.
Definition common.h:537
Definition utility.h:496
mem_type_e
Definition common.h:204
@ system
System memory.
speaker_e
Definition common.h:169
@ BACK_LEFT
Back left.
Definition common.h:174
@ LOW_FREQUENCY
Low frequency.
Definition common.h:173
@ SIDE_RIGHT
Side right.
Definition common.h:177
@ MAX_SPEAKERS
Maximum number of speakers.
Definition common.h:178
@ FRONT_LEFT
Front left.
Definition common.h:170
@ SIDE_LEFT
Side left.
Definition common.h:176
@ FRONT_CENTER
Front center.
Definition common.h:172
@ BACK_RIGHT
Back right.
Definition common.h:175
@ FRONT_RIGHT
Front right.
Definition common.h:171
std::vector< supported_gamepad_t > & supported_gamepads(input_t *input)
Gets the supported gamepads for this platform backend.
Definition inputtino.cpp:150
std::shared_ptr< display_t > display(mem_type_e hwdevice_type, const std::string &display_name, const video::config_t &config)
Get the display_t instance for the given hwdevice_type. If display_name is empty, use the first monit...
Definition misc.cpp:909
pix_fmt_e
Definition common.h:213
@ yuv420p10
YUV 4:2:0 10-bit.
@ yuv444p16
Planar 10-bit (shifted to 16-bit) YUV 4:4:4.
@ yuv420p
YUV 4:2:0.
std::filesystem::path appdata()
Performs migration if necessary, then returns the appdata directory.
Definition misc.cpp:109
qos_data_type_e
Definition common.h:718
std::unique_ptr< high_precision_timer > create_high_precision_timer()
Create platform-specific timer capable of high-precision sleep.
Definition misc.cpp:1019
bool needs_encoder_reenumeration()
Check if GPUs/drivers have changed since the last call to this function.
Definition misc.cpp:903
gamepad_feedback_e
Definition common.h:98
@ rumble_triggers
Rumble triggers.
@ set_motion_event_state
Set motion event state.
thread_priority_e
Definition common.h:611
@ critical
Critical priority.
@ high
High priority.
@ normal
Normal priority.
std::string get_host_name()
Returns the current computer name in UTF-8.
Definition misc.cpp:802
capture_e
Definition common.h:440
@ timeout
Timeout.
@ reinit
Need to reinitialize.
@ interrupted
Capture was interrupted.
Declarations for the configuration of Sunshine.
std::unique_ptr< platf::deinit_t > init(const std::filesystem::path &persistence_filepath, const config::video_t &video_config)
Initialize the implementation and perform the initial state recovery (if needed).
Definition display_device.cpp:721
Declarations for logging related functions.
Standalone NVENC encoder.
Definition nvenc_base.cpp:86
Definition common.h:386
virtual int prepare_to_derive_context(int hw_device_type)
Prepare to derive a context.
Definition common.h:428
virtual void init_codec_options(AVCodecContext *ctx, AVDictionary **options)
Provides a hook for allow platform-specific code to adjust codec options.
Definition common.h:421
virtual int set_frame(AVFrame *frame, AVBufferRef *hw_frames_ctx)
Set the frame to be encoded.
Definition common.h:404
virtual void init_hwframes(AVHWFramesContext *frames)
Initialize the hwframes context.
Definition common.h:414
Definition common.h:657
buffer_descriptor_t buffer_for_payload_offset(ptrdiff_t offset)
Returns a payload buffer descriptor for the given payload offset.
Definition common.h:686
Definition common.h:646
Definition common.h:377
Definition common.h:280
Definition common.h:306
Definition common.h:105
Definition common.h:269
Definition common.h:295
Definition common.h:259
Definition common.h:286
Definition common.h:885
virtual void sleep_for(const std::chrono::nanoseconds &duration)=0
Sleep for the duration.
Definition common.h:341
Definition common.h:433
Definition common.h:323
Definition common.h:704
Definition common.h:369
Definition common.h:363
Definition common.h:92
Definition common.h:312
Definition common.h:246
Definition utility.h:951
Definition video.h:21
Definition video_colorspace.h:20
Declarations for thread-safe data structures.
Declarations for utility functions.
Declarations for colorspace functions.