## File: README.md

# Apollo

Apollo is a self-hosted desktop stream host for [Artemis(Moonlight Noir)](https://github.com/ClassicOldSong/moonlight-android). Offering low latency, native client resolution, cloud gaming server capabilities with support for AMD, Intel, and Nvidia GPUs for hardware encoding. Software encoding is also available. A web UI is provided to allow configuration and client pairing from your favorite web browser. Pair from the local server or any mobile device.

Major features:

- [x] Built-in Virtual Display with HDR support that matches the resolution/framerate config of your client automatically
- [x] Permission management for clients
- [x] Clipboard sync
- [x] Commands for client connection/disconnection (checkout [Auto pause/resume games](https://github.com/ClassicOldSong/Apollo/wiki/Auto-pause-resume-games))
- [x] Input only mode

## Usage

Refer to LizardByte's documentation hosted on [Read the Docs](https://docs.lizardbyte.dev/projects/sunshine) for now.

Currently Virtual Display support is Windows only, Linux support is planned and will be implemented in the future.

## About Permission System

Check out the [Wiki](https://github.com/ClassicOldSong/Apollo/wiki/Permission-System)

> [!NOTE]
> The **FIRST** client paired with Apollo will be granted with FULL permissions, then other newly paired clients will only be granted with `View Streams` and `List Apps` permission. If you encounter `Permission Denied` error when trying to launch any app, go check the permission for that device and grant `Launch Apps` permission. The same applies to the situation when you find that you can't move mouse or type with keyboard on newly paired clients, grant the corresponding client `Mouse Input` and `Keyboard Input` permissions.

## About Virtual Display

> [!WARNING]
> ***It is highly recommend to remove any other virtual display solutions from your system and Apollo/Sunshine config, to reduce confusions and compatibility issues.***

> [!NOTE]
> **TL;DR** Just treat your Artemis/Moonlight client like a dedicated PnP monitor with Apollo.

Apollo uses SudoVDA for virtual display. It features auto resolution and framerate matching for your Artemis/Moonlight clients. The virtual display is created upon the stream starts and removed once the app quits. **If you do not see a new virtual display added or removed when the stream starts or stops, there may be a driver misconfiguration, or another persistent virtual display might still be active.**

The virtual display works just like any physically attached monitors with SudoVDA, there's completely no need for a super complicated solution to "fix" resolution configurations for your devices. Unlike all other solutions that reuses one identity or generate a random one each time for any virtual display sessions, **Apollo assigns a fixed identity for each Artemis/Moonlight client, so your display configuration will be automatically remembered and managed by Windows natively.**

## Configuration for dual GPU laptops

Apollo supports dual GPUs seamlessly.

If you want to use your dGPU, just set the `Adapter Name` to your dGPU and enable `Headless mode` in `Audio/Video` tab, save and restart your computer. No dummy plug is needed any more, the image will be rendered and encoded directly from your dGPU.

## About HDR

HDR starts supporting from Windows 11 23H2 and generally supported on 24H2. Some systems might not have HDR toggle on 23H2 and you just need to upgrade to 24H2. Any system lower than 23H2/Windows 10 will not have HDR option available.

> [!NOTE]
> The below section is written for professional media workers. It doesn't stop you from enabling HDR if you know what you're doing and have deep understanding about how HDR works.
>
> Apollo and SudoVDA can handle HDR just fine like any other streaming solutions.
>
> If you have had good experience with HDR previously, you can safely ignore this section.
>
> If you're curious, read on, but don't blame Apollo for poor HDR support.

Whether HDR streaming looks good, it depends completely on your client.

In short, ICC color correction should be totally useless while streaming HDR. It's your client's job to get HDR content displayed right, not the host. But in fact, it does affect the captured video stream and reflect changes on devices that can handle HDR correctly. On other devices that can't, the info is not respected at all.

It's very complicated to explain why HDR is a total mess, and why enabling HDR makes the image appear dark/yellow. If it's your first time got HDR streaming working, and thinks HDR looks awful, you're right, but that's not Apollo's fault, it's your device that tone mapped SDR content to the maximum of the capability of its screen, there's no headroom for anything beyond that actual peak brightness for HDR. For details, please take a look [here](https://github.com/ClassicOldSong/Apollo/issues/164).

For client devices, usually Apple products that have HDR capability can be trusted to have good results, other than that, your luck depends.


DEPRECATION ALERT

Enabling HDR is **generally not recommended** with **ANY streaming solutions** at this moment, probably in the long term. The issue with **HDR itself** is huge, with loads of semi-incompatible standards, and massive variance between device configurations and capabilities. Game support for HDR is still choppy.

SDR actually provides much more stable color accuracy, and are widely supported throughout most devices you can imagine. For games, art style can easily overcome the shortcoming with no HDR, and SDR has pretty standard workflows to ensure their visual performance. So HDR isn't *that* important in most of the cases.



## How to run multiple instances of Apollo for multiple virtual displays

Follow the instructions in the [Wiki](https://github.com/ClassicOldSong/Apollo/wiki/How-to-start-multiple-instances-of-Apollo).

## FAQ
Moved to [WiKi](https://github.com/ClassicOldSong/Apollo/wiki/FAQ)

## Stuttering Clinic
Here're some common causes and solutions for stutters: [WiKi](https://github.com/ClassicOldSong/Apollo/wiki/Stuttering-Clinic).

## Device specific setups
- Pixel devices might not be able to use native resolution:
  - Change the device resolution to Max: https://github.com/ClassicOldSong/Apollo/issues/700

## System Requirements

> **Warning**: This table is a work in progress. Do not purchase hardware based on this.

**Minimum Requirements**

| **Component** | **Description** |
|---------------|-----------------|
| GPU           | AMD: VCE 1.0 or higher, see: [obs-amd hardware support](https://github.com/obsproject/obs-amd-encoder/wiki/Hardware-Support) |
|               | Intel: VAAPI-compatible, see: [VAAPI hardware support](https://www.intel.com/content/www/us/en/developer/articles/technical/linuxmedia-vaapi.html) |
|               | Nvidia: NVENC enabled cards, see: [nvenc support matrix](https://developer.nvidia.com/video-encode-and-decode-gpu-support-matrix-new) |
| CPU           | AMD: Ryzen 3 or higher |
|               | Intel: Core i3 or higher |
| RAM           | 4GB or more |
| OS            | Windows: 10+ (Windows Server requires [manual installation](https://github.com/nefarius/ViGEmBus/issues/153) for gamepad support) |
|               | macOS: 12+ |
|               | Linux/Debian: 11 (bullseye) |
|               | Linux/Fedora: 39+ |
|               | Linux/Ubuntu: 22.04+ (jammy) |
| Network       | Host: 5GHz, 802.11ac |
|               | Client: 5GHz, 802.11ac |

**4k Suggestions**

| **Component** | **Description** |
|---------------|-----------------|
| GPU           | AMD: Video Coding Engine 3.1 or higher |
|               | Intel: HD Graphics 510 or higher |
|               | Nvidia: GeForce GTX 1080 or higher |
| CPU           | AMD: Ryzen 5 or higher |
|               | Intel: Core i5 or higher |
| Network       | Host: CAT5e ethernet or better |
|               | Client: CAT5e ethernet or better |

**HDR Suggestions**

| **Component** | **Description** |
|---------------|-----------------|
| GPU           | AMD: Video Coding Engine 3.4 or higher |
|               | Intel: UHD Graphics 730 or higher |
|               | Nvidia: Pascal-based GPU (GTX 10-series) or higher |
| CPU           | AMD: todo |
|               | Intel: todo |
| Network       | Host: CAT5e ethernet or better |
|               | Client: CAT5e ethernet or better |

## Integrations

SudoVDA: Virtual Display Adapter Driver used in Apollo

[Artemis](https://github.com/ClassicOldSong/moonlight-android): Integrated Virtual Display options control from client side

**NOTE**: Artemis currently supports Android only. Other platforms will come later.

## Support

Currently support is only provided via GitHub Issues/Discussions.

No real time chat support will ever be provided for Apollo and Artemis. Including but not limited to:

- Discord
- Telegram
- Whatsapp
- QQ
- WeChat 

> When there's a chat, there're dramas. -- Confucius

## Downloads

### Direct Download

**Recommended**

[Releases](https://github.com/ClassicOldSong/Apollo/releases)

### WinGet

**Note:** Community maintained

In an elevated PowerShell window, run

```pwsh
winget install ClassicOldSong.Apollo

```

You'll need WinGet installed first.

### Chocolatey

**Note:** Community maintained

You can also install the apollo streaming server with chocolatey.

Install Chocolatey if you don't have it, then run the following command in an elevated PowerShell/CMD window:

```pwsh
choco upgrade apollo -y 
```

Same command can be used to upgrade, add to a scheduled task to automate updates.

See more details on the chocolatey package [here](https://community.chocolatey.org/packages/apollo)

## Disclaimer

I got kicked from Moonlight and Sunshine's Discord server and banned from Sunshine's GitHub repo literally for helping people out.

This is what I got for finding a bug, opened an issue, getting no response, troubleshoot myself, fixed the issue myself, shared it by PR to the main repo hoping my efforts can help someone else during the maintenance gap.

Yes, I'm going away. [Apollo](https://github.com/ClassicOldSong/Apollo) and [Artemis(Moonlight Noir)](https://github.com/ClassicOldSong/moonlight-android) will no longer be compatible with OG Sunshine and OG Moonlight eventually, but they'll work even better with much more carefully designed features.

The Moonlight repo had stayed silent for 5 months, with nobody actually responding to issues, and people are getting totally no help besides the limited FAQ in their Discord server. I tried to answer issues and questions, solve problems within my ability but I got kicked out just for helping others.

**PRs for feature improvements are welcomed here unlike the main repo, your ideas are more likely to be appreciated and your efforts are actually being respected. We welcome people who can and willing to share their efforts, helping yourselves and other people in need.**

**Update**: They have contacted me and apologized for this incident, but the fact it **happened** still motivated me to start my own fork.

## License

GPLv3

---

## File: docs/api.md

# API

Sunshine has a RESTful API which can be used to interact with the service.

Unless otherwise specified, authentication is required for all API calls. You can authenticate using
basic authentication with the admin username and password.

@htmlonly
<script src="api.js"></script>
@endhtmlonly

## GET /api/apps
@copydoc confighttp::getApps()

## POST /api/apps
@copydoc confighttp::saveApp()

## POST /api/apps/close
@copydoc confighttp::closeApp()

## DELETE /api/apps/{index}
@copydoc confighttp::deleteApp()

## GET /api/clients/list
@copydoc confighttp::getClients()

## POST /api/clients/unpair
@copydoc confighttp::unpair()

## POST /api/clients/unpair-all
@copydoc confighttp::unpairAll()

## GET /api/config
@copydoc confighttp::getConfig()

## GET /api/configLocale
@copydoc confighttp::getLocale()

## POST /api/config
@copydoc confighttp::saveConfig()

## POST /api/covers/upload
@copydoc confighttp::uploadCover()

## GET /api/logs
@copydoc confighttp::getLogs()

## POST /api/password
@copydoc confighttp::savePassword()

## POST /api/pin
@copydoc confighttp::savePin()

## POST /api/reset-display-device-persistence
@copydoc confighttp::resetDisplayDevicePersistence()

## POST /api/restart
@copydoc confighttp::restart()



| Previous                                    |                                  Next |
|:--------------------------------------------|--------------------------------------:|
| [Performance Tuning](performance_tuning.md) | [Troubleshooting](troubleshooting.md) |




  
  [TOC]

---

## File: docs/app_examples.md

# App Examples
Since not all applications behave the same, we decided to create some examples to help you get started adding games
and applications to Sunshine.

> [!TIP]
> Throughout these examples, any fields not shown are left blank. You can enhance your experience by
> adding an image or a log file (via the `Output` field).

> [!WARNING]
> When a working directory is not specified, it defaults to the folder where the target application resides.


## Common Examples

### Desktop

| Field            | Value                      |
|------------------|----------------------------|
| Application Name | @code{}Desktop@endcode     |
| Image            | @code{}desktop.png@endcode |

### Steam Big Picture

> [!NOTE]
> Steam is launched as a detached command because Steam starts with a process that self updates itself and the original
> process is killed.

@tabs{
  @tab{Linux | 
    \| Field                        \| Value                                                \|
    \|------------------------------\|------------------------------------------------------\|
    \| Application Name             \| @code{}Steam Big Picture@endcode                     \|
    \| Command Preporations -> Undo \| @code{}setsid steam steam://close/bigpicture@endcode \|
    \| Detached Commands            \| @code{}setsid steam steam://open/bigpicture@endcode  \|
    \| Image                        \| @code{}steam.png@endcode                             \|
  }
  @tab{macOS | 
    \| Field                        \| Value                                          \|
    \|------------------------------\|------------------------------------------------\|
    \| Application Name             \| @code{}Steam Big Picture@endcode               \|
    \| Command Preporations -> Undo \| @code{}open steam://close/bigpicture@endcode   \|
    \| Detached Commands            \| @code{}open steam://open/bigpicture@endcode    \|
    \| Image                        \| @code{}steam.png@endcode                       \|
  }
  @tab{Windows | 
    \| Field                        \| Value                                     \|
    \|------------------------------\|-------------------------------------------\|
    \| Application Name             \| @code{}Steam Big Picture@endcode          \|
    \| Command Preporations -> Undo \| @code{}steam://close/bigpicture@endcode   \|
    \| Detached Commands            \| @code{}steam://open/bigpicture@endcode    \|
    \| Image                        \| @code{}steam.png@endcode                  \|
  }
}

### Epic Game Store game

> [!NOTE]
> Using the URI method will be the most consistent between various games.

#### URI

@tabs{
  @tab{Windows | 
    \| Field            \| Value                                                                                                                                                 \|
    \|------------------\|-------------------------------------------------------------------------------------------------------------------------------------------------------\|
    \| Application Name \| @code{}Surviving Mars@endcode                                                                                                                         \|
    \| Commands         \| @code{}com.epicgames.launcher://apps/d759128018124dcabb1fbee9bb28e178%3A20729b9176c241f0b617c5723e70ec2d%3AOvenbird?action=launch&silent=true@endcode \|
  }
}

#### Binary (w/ working directory
@tabs{
  @tab{Windows | 
    \| Field             \| Value                                                      \|
    \|-------------------\|------------------------------------------------------------\|
    \| Application Name  \| @code{}Surviving Mars@endcode                              \|
    \| Command           \| @code{}MarsEpic.exe@endcode                                \|
    \| Working Directory \| @code{}"C:\Program Files\Epic Games\SurvivingMars"@endcode \|
  }
}

#### Binary (w/o working directory)
@tabs{
  @tab{Windows | 
    \| Field             \| Value                                                                   \|
    \|-------------------\|-------------------------------------------------------------------------\|
    \| Application Name  \| @code{}Surviving Mars@endcode                                           \|
    \| Command           \| @code{}"C:\Program Files\Epic Games\SurvivingMars\MarsEpic.exe"@endcode \|
  }
}

### Steam game

> [!NOTE]
> Using the URI method will be the most consistent between various games.

#### URI

@tabs{
  @tab{Linux | 
    \| Field             \| Value                                                \|
    \|-------------------\|------------------------------------------------------\|
    \| Application Name  \| @code{}Surviving Mars@endcode                        \|
    \| Detached Commands \| @code{}setsid steam steam://rungameid/464920@endcode \|
  }
  @tab{macOS | 
    \| Field             \| Value                                        \|
    \|-------------------\|----------------------------------------------\|
    \| Application Name  \| @code{}Surviving Mars@endcode                \|
    \| Detached Commands \| @code{}open steam://rungameid/464920@endcode \|
  }
  @tab{Windows | 
    \| Field             \| Value                                   \|
    \|-------------------\|-----------------------------------------\|
    \| Application Name  \| @code{}Surviving Mars@endcode           \|
    \| Detached Commands \| @code{}steam://rungameid/464920@endcode \|
  }
}

#### Binary (w/ working directory
@tabs{
  @tab{Linux | 
    \| Field             \| Value                                                        \|
    \|-------------------\|--------------------------------------------------------------\|
    \| Application Name  \| @code{}Surviving Mars@endcode                                \|
    \| Command           \| @code{}MarsSteam@endcode                                     \|
    \| Working Directory \| @code{}~/.steam/steam/SteamApps/common/Survivng Mars@endcode \|
  }
  @tab{macOS | 
    \| Field             \| Value                                                        \|
    \|-------------------\|--------------------------------------------------------------\|
    \| Application Name  \| @code{}Surviving Mars@endcode                                \|
    \| Command           \| @code{}MarsSteam@endcode                                     \|
    \| Working Directory \| @code{}~/.steam/steam/SteamApps/common/Survivng Mars@endcode \|
  }
  @tab{Windows | 
    \| Field             \| Value                                                                         \|
    \|-------------------\|-------------------------------------------------------------------------------\|
    \| Application Name  \| @code{}Surviving Mars@endcode                                                 \|
    \| Command           \| @code{}MarsSteam.exe@endcode                                                  \|
    \| Working Directory \| @code{}"C:\Program Files (x86)\Steam\steamapps\common\Surviving Mars"@endcode \|
  }
}

#### Binary (w/o working directory)
@tabs{
  @tab{Linux | 
    \| Field             \| Value                                                                  \|
    \|-------------------\|------------------------------------------------------------------------\|
    \| Application Name  \| @code{}Surviving Mars@endcode                                          \|
    \| Command           \| @code{}~/.steam/steam/SteamApps/common/Survivng Mars/MarsSteam@endcode \|
  }
  @tab{macOS | 
    \| Field             \| Value                                                                  \|
    \|-------------------\|------------------------------------------------------------------------\|
    \| Application Name  \| @code{}Surviving Mars@endcode                                          \|
    \| Command           \| @code{}~/.steam/steam/SteamApps/common/Survivng Mars/MarsSteam@endcode \|
  }
  @tab{Windows | 
    \| Field             \| Value                                                                                       \|
    \|-------------------\|---------------------------------------------------------------------------------------------\|
    \| Application Name  \| @code{}Surviving Mars@endcode                                                               \|
    \| Command           \| @code{}"C:\Program Files (x86)\Steam\steamapps\common\Surviving Mars\MarsSteam.exe"@endcode \|
  }
}

### Prep Commands

#### Changing Resolution and Refresh Rate

##### Linux

###### X11

| Prep Step | Command                                                                                                                               |
|-----------|---------------------------------------------------------------------------------------------------------------------------------------|
| Do        | @code{}sh -c "xrandr --output HDMI-1 --mode ${SUNSHINE_CLIENT_WIDTH}x${SUNSHINE_CLIENT_HEIGHT} --rate ${SUNSHINE_CLIENT_FPS}"@endcode |
| Undo      | @code{}xrandr --output HDMI-1 --mode 3840x2160 --rate 120@endcode                                                                     |

> [!TIP]
> The above only works if the xrandr mode already exists. You will need to create new modes to stream to macOS
> and iOS devices, since they use non-standard resolutions.
>
> You can update the ``Do`` command to this:
> ```bash
> bash -c "${HOME}/scripts/set-custom-res.sh \"${SUNSHINE_CLIENT_WIDTH}\" \"${SUNSHINE_CLIENT_HEIGHT}\" \"${SUNSHINE_CLIENT_FPS}\""
> ```
>
> The `set-custom-res.sh` will have this content:
> ```bash
> #!/bin/bash
> set -e
>
> # Get params and set any defaults
> width=${1:-1920}
> height=${2:-1080}
> refresh_rate=${3:-60}
>
> # You may need to adjust the scaling differently so the UI/text isn't too small / big
> scale=${4:-0.55}
>
> # Get the name of the active display
> display_output=$(xrandr | grep " connected" | awk '{ print $1 }')
>
> # Get the modeline info from the 2nd row in the cvt output
> modeline=$(cvt ${width} ${height} ${refresh_rate} | awk 'FNR == 2')
> xrandr_mode_str=${modeline//Modeline \"*\" /}
> mode_alias="${width}x${height}"
>
> echo "xrandr setting new mode ${mode_alias} ${xrandr_mode_str}"
> xrandr --newmode ${mode_alias} ${xrandr_mode_str}
> xrandr --addmode ${display_output} ${mode_alias}
>
> # Reset scaling
> xrandr --output ${display_output} --scale 1
>
> # Apply new xrandr mode
> xrandr --output ${display_output} --primary --mode ${mode_alias} --pos 0x0 --rotate normal --scale ${scale}
>
> # Optional reset your wallpaper to fit to new resolution
> # xwallpaper --zoom /path/to/wallpaper.png
> ```

###### Wayland (wlroots, e.g. hyprland)

| Prep Step | Command                                                                                                                                  |
|-----------|------------------------------------------------------------------------------------------------------------------------------------------|
| Do        | @code{}sh -c "wlr-xrandr --output HDMI-1 --mode \"${SUNSHINE_CLIENT_WIDTH}x${SUNSHINE_CLIENT_HEIGHT}@${SUNSHINE_CLIENT_FPS}Hz\""@endcode |
| Undo      | @code{}wlr-xrandr --output HDMI-1 --mode 3840x2160@120Hz@endcode                                                                         |

> [!TIP]
> `wlr-xrandr` only works with wlroots-based compositors.

###### Gnome (X11)

| Prep Step | Command                                                                                                                               |
|-----------|---------------------------------------------------------------------------------------------------------------------------------------|
| Do        | @code{}sh -c "xrandr --output HDMI-1 --mode ${SUNSHINE_CLIENT_WIDTH}x${SUNSHINE_CLIENT_HEIGHT} --rate ${SUNSHINE_CLIENT_FPS}"@endcode |
| Undo      | @code{}xrandr --output HDMI-1 --mode 3840x2160 --rate 120@endcode                                                                     |

###### Gnome (Wayland)

| Prep Step | Command                                                                                                                                                                                               |
|-----------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Do        | @code{}sh -c "displayconfig-mutter set --connector HDMI-1 --resolution ${SUNSHINE_CLIENT_WIDTH}x${SUNSHINE_CLIENT_HEIGHT} --refresh-rate ${SUNSHINE_CLIENT_FPS} --hdr ${SUNSHINE_CLIENT_HDR}"@endcode |
| Undo      | @code{}displayconfig-mutter set --connector HDMI-1 --resolution 3840x2160 --refresh-rate 120 --hdr false@endcode                                                                                      |

Installation instructions for displayconfig-mutter can be [found here](https://github.com/eaglesemanation/displayconfig-mutter). Alternatives include
[gnome-randr-rust](https://github.com/maxwellainatchi/gnome-randr-rust) and [gnome-randr.py](https://gitlab.com/Oschowa/gnome-randr), but both of those are
unmaintained and do not support newer Mutter features such as HDR and VRR.

> [!TIP]
> HDR support has been added to Gnome 48, to check if your display supports it, you can run this:
> ```
> displayconfig-mutter list
> ```
> If it doesn't, then remove ``--hdr`` flag from both ``Do`` and ``Undo`` steps.

###### KDE Plasma (Wayland, X11)

| Prep Step | Command                                                                                                                              |
|-----------|--------------------------------------------------------------------------------------------------------------------------------------|
| Do        | @code{}sh -c "kscreen-doctor output.HDMI-A-1.mode.${SUNSHINE_CLIENT_WIDTH}x${SUNSHINE_CLIENT_HEIGHT}@${SUNSHINE_CLIENT_FPS}"@endcode |
| Undo      | @code{}kscreen-doctor output.HDMI-A-1.mode.3840x2160@120@endcode                                                                     |

> [!CAUTION]
> The names of your displays will differ between X11 and Wayland.
> Be sure to use the correct name, depending on your session manager.
> e.g., On X11, the monitor may be called ``HDMI-A-0``, but on Wayland, it may be called ``HDMI-A-1``.

> [!TIP]
> Replace ``HDMI-A-1`` with the display name of the monitor you would like to use for Moonlight.
> You can list the monitors available to you with:
> ```
> kscreen-doctor -o
> ```
>
> These will also give you the supported display properties for each monitor. You can select them either by
> hard-coding their corresponding number (e.g. ``kscreen-doctor output.HDMI-A1.mode.0``) or using the above
> ``do`` command to fetch the resolution requested by your Moonlight client
> (which has a chance of not being supported by your monitor).

###### NVIDIA

| Prep Step | Command                                                                                                                                                                                                                        |
|-----------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Do        | @code{}sh -c "nvidia-settings -a CurrentMetaMode=\"HDMI-1: nvidia-auto-select { ViewPortIn=${SUNSHINE_CLIENT_WIDTH}x${SUNSHINE_CLIENT_HEIGHT}, ViewPortOut=${SUNSHINE_CLIENT_WIDTH}x${SUNSHINE_CLIENT_HEIGHT}+0+0 }\""@endcode |
| Undo      | @code{}nvidia-settings -a CurrentMetaMode=\"HDMI-1: nvidia-auto-select { ViewPortIn=3840x2160, ViewPortOut=3840x2160+0+0 }"@endcode                                                                                            |

##### macOS

###### displayplacer

> [!NOTE]
> This example uses the `displayplacer` tool to change the resolution.
> This tool can be installed following instructions in their
> [GitHub repository](https://github.com/jakehilborn/displayplacer).

| Prep Step | Command                                                                                                                                                                  |
|-----------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Do        | @code{}sh -c "displayplacer \"id:<screenId> res:${SUNSHINE_CLIENT_WIDTH}x${SUNSHINE_CLIENT_HEIGHT} hz:${SUNSHINE_CLIENT_FPS} scaling:on origin:(0,0) degree:0\""@endcode |
| Undo      | @code{}displayplacer "id:<screenId> res:3840x2160 hz:120 scaling:on origin:(0,0) degree:0"@endcode                                                                       |

##### Windows
Sunshine has built-in support for changing the resolution and refresh rate on Windows. If you prefer to use a
third-party tool, you can use *QRes* as an example.

###### QRes

> [!NOTE]
> This example uses the *QRes* tool to change the resolution and refresh rate.
> This tool can be downloaded from their [SourceForge repository](https://sourceforge.net/projects/qres).

| Prep Step | Command                                                                                                                   |
|-----------|---------------------------------------------------------------------------------------------------------------------------|
| Do        | @code{}cmd /C "FullPath\qres.exe /x:%SUNSHINE_CLIENT_WIDTH% /y:%SUNSHINE_CLIENT_HEIGHT% /r:%SUNSHINE_CLIENT_FPS%"@endcode |
| Undo      | @code{}FullPath\qres.exe /x:3840 /y:2160 /r:120@endcode                                                                   |

### Additional Considerations

#### Linux (Flatpak)

> [!CAUTION]
> Because Flatpak packages run in a sandboxed environment and do not normally have access to the
> host, the Flatpak of Sunshine requires commands to be prefixed with `flatpak-spawn --host`.

#### Windows
**Elevating Commands (Windows)**

If you've installed Sunshine as a service (default), you can specify if a command should be elevated with
administrative privileges. Simply enable the elevated option in the WEB UI, or add it to the JSON configuration.
This is an option for both prep-cmd and regular commands and will launch the process with the current user without a
UAC prompt.

**Example**
```json
{
  "name": "Game With AntiCheat that Requires Admin",
  "output": "",
  "cmd": "ping 127.0.0.1",
  "exclude-global-prep-cmd": false,
  "elevated": true,
  "prep-cmd": [
    {
      "do": "powershell.exe -command \"Start-Streaming\"",
      "undo": "powershell.exe -command \"Stop-Streaming\"",
      "elevated": false
    }
  ],
  "image-path": ""
}
```



| Previous                          |                                    Next |
|:----------------------------------|----------------------------------------:|
| [Configuration](configuration.md) | [Awesome-Sunshine](awesome_sunshine.md) |




  
  [TOC]

---

## File: docs/awesome_sunshine.md

# Awesome-Sunshine

@htmlonly
<script type="module" src="https://md-block.verou.me/md-block.js"></script>
<md-block
  hlinks=""
  hmin="2"
  src="https://raw.githubusercontent.com/LizardByte/awesome-sunshine/master/README.md">
</md-block>
@endhtmlonly



| Previous                        |                Next |
|:--------------------------------|--------------------:|
| [App Examples](app_examples.md) | [Guides](guides.md) |




  
  [TOC]

---

## File: docs/building.md

# Building
Sunshine binaries are built using [CMake](https://cmake.org) and requires `cmake` > 3.25.

## Building Locally

### Compiler
It is recommended to use one of the following compilers:

| Compiler    | Version |
|:------------|:--------|
| GCC         | 13+     |
| Clang       | 17+     |
| Apple Clang | 15+     |

### Dependencies

#### Linux
Dependencies vary depending on the distribution. You can reference our
[linux_build.sh](https://github.com/LizardByte/Sunshine/blob/master/scripts/linux_build.sh) script for a list of
dependencies we use in Debian-based and Fedora-based distributions. Please submit a PR if you would like to extend the
script to support other distributions.

##### CUDA Toolkit
Sunshine requires CUDA Toolkit for NVFBC capture. There are two caveats to CUDA:

1. The version installed depends on the version of GCC.
2. The version of CUDA you use will determine compatibility with various GPU generations.
   At the time of writing, the recommended version to use is CUDA ~12.9.
   See [CUDA compatibility](https://docs.nvidia.com/deploy/cuda-compatibility/index.html) for more info.

> [!NOTE]
> To install older versions, select the appropriate run file based on your desired CUDA version and architecture
> according to [CUDA Toolkit Archive](https://developer.nvidia.com/cuda-toolkit-archive)

#### macOS
You can either use [Homebrew](https://brew.sh) or [MacPorts](https://www.macports.org) to install dependencies.

##### Homebrew
```bash
dependencies=(
  "boost"  # Optional
  "cmake"
  "doxygen"  # Optional, for docs
  "graphviz"  # Optional, for docs
  "icu4c"  # Optional, if boost is not installed
  "miniupnpc"
  "ninja"
  "node"
  "openssl@3"
  "opus"
  "pkg-config"
)
brew install "${dependencies[@]}"
```

If there are issues with an SSL header that is not found:

@tabs{
  @tab{ Intel | ```bash
    ln -s /usr/local/opt/openssl/include/openssl /usr/local/include/openssl
    ```}
  @tab{ Apple Silicon | ```bash
    ln -s /opt/homebrew/opt/openssl/include/openssl /opt/homebrew/include/openssl
    ```
  }
}

##### MacPorts
```bash
dependencies=(
  "cmake"
  "curl"
  "doxygen"  # Optional, for docs
  "graphviz"  # Optional, for docs
  "libopus"
  "miniupnpc"
  "ninja"
  "npm9"
  "pkgconfig"
)
sudo port install "${dependencies[@]}"
```

#### Windows
First you need to install [MSYS2](https://www.msys2.org), then startup "MSYS2 UCRT64" and execute the following
commands.

##### Update all packages
```bash
pacman -Syu
```

##### Install dependencies
```bash
dependencies=(
  "git"
  "mingw-w64-ucrt-x86_64-boost"  # Optional
  "mingw-w64-ucrt-x86_64-cmake"
  "mingw-w64-ucrt-x86_64-cppwinrt"
  "mingw-w64-ucrt-x86_64-curl-winssl"
  "mingw-w64-ucrt-x86_64-doxygen"  # Optional, for docs... better to install official Doxygen
  "mingw-w64-ucrt-x86_64-graphviz"  # Optional, for docs
  "mingw-w64-ucrt-x86_64-MinHook"
  "mingw-w64-ucrt-x86_64-miniupnpc"
  "mingw-w64-ucrt-x86_64-nsis"
  "mingw-w64-ucrt-x86_64-onevpl"
  "mingw-w64-ucrt-x86_64-openssl"
  "mingw-w64-ucrt-x86_64-opus"
  "mingw-w64-ucrt-x86_64-toolchain"
  "mingw-w64-ucrt-x86_64-nlohmann_json"
)
pacman -S "${dependencies[@]}"
```

##### Install Node.js
Install Node.js separately from [nodejs.org](https://nodejs.org/) (LTS or current) or via
[nvm-windows](https://github.com/coreybutler/nvm-windows). Don't install MSYS2's
`mingw-w64-ucrt-x86_64-nodejs` — it's compiled with the MSYS2 gcc-16 libstdc++ which has
a `std::bad_weak_ptr` regression that crashes Node during process init (see
[apache/arrow#49958](https://github.com/apache/arrow/issues/49958) for the upstream
toolchain trail). The official MSVC-built Node.js isn't affected.

Make sure `node.exe` is on `PATH` before running `cmake` — the `web-ui` CMake target
invokes `npm install` via `find_program(NPM npm)`, so the official Node's `npm` must be
visible to CMake.

### Clone
Ensure [git](https://git-scm.com) is installed on your system, then clone the repository using the following command:

```bash
git clone https://github.com/ClassicOldSong/Apollo.git --recurse-submodules
cd Apollo
mkdir build
```

### Build

```bash
cmake -B build -G Ninja -S .
ninja -C build
```

> [!TIP]
> Available build options can be found in
> [options.cmake](https://github.com/LizardByte/Sunshine/blob/master/cmake/prep/options.cmake).

### Package

@tabs{
  @tab{Linux | @tabs{
    @tab{deb | ```bash
      cpack -G DEB --config ./build/CPackConfig.cmake
      ```}
    @tab{rpm | ```bash
      cpack -G RPM --config ./build/CPackConfig.cmake
      ```}
  }}
  @tab{macOS | @tabs{
    @tab{DragNDrop | ```bash
      cpack -G DragNDrop --config ./build/CPackConfig.cmake
      ```}
  }}
  @tab{Windows | @tabs{
    @tab{Installer | ```bash
      cpack -G NSIS --config ./build/CPackConfig.cmake
      ```}
    @tab{Portable | ```bash
      cpack -G ZIP --config ./build/CPackConfig.cmake
      ```}
  }}
}

### Remote Build
It may be beneficial to build remotely in some cases. This will enable easier building on different operating systems.

1. Fork the project
2. Activate workflows
3. Trigger the *CI* workflow manually
4. Download the artifacts/binaries from the workflow run summary



| Previous                              |                            Next |
|:--------------------------------------|--------------------------------:|
| [Troubleshooting](troubleshooting.md) | [Contributing](contributing.md) |




  
  [TOC]

---

## File: docs/configuration.md

# Configuration

@admonition{ Host authority | @htmlonly
By providing the host authority (URI + port), you can easily open each configuration option in the config UI.

<script src="configuration.js"></script>
**Host authority: ** 
@endhtmlonly
}

Sunshine will work with the default settings for most users. In some cases you may want to configure Sunshine further.

The default location for the configuration file is listed below. You can use another location if you
choose, by passing in the full configuration file path as the first argument when you start Sunshine.

**Example**
```bash
sunshine ~/sunshine_config.conf
```

The default location of the `apps.json` is the same as the configuration file. You can use a custom
location by modifying the configuration file.

**Default Config Directory**

| OS      | Location                                        |
|---------|-------------------------------------------------|
| Docker  | @code{}/config@endcode                          |
| Linux   | @code{}~/.config/sunshine@endcode               |
| macOS   | @code{}~/.config/sunshine@endcode               |
| Windows | @code{}%ProgramFiles%\\Sunshine\\config@endcode |

Although it is recommended to use the configuration UI, it is possible manually configure Sunshine by
editing the `conf` file in a text editor. Use the examples as reference.

## General

### locale



| Description | The locale used for Sunshine's user interface. |  |
| --- | --- | --- |
| Default | @code{}
            en
            @endcode |  |
| Example | @code{}
            locale = en
            @endcode |  |
| Choices | bg | Bulgarian |
| cs | Czech |  |
| de | German |  |
| en | English |  |
| en_GB | English (UK) |  |
| en_US | English (United States) |  |
| es | Spanish |  |
| fr | French |  |
| it | Italian |  |
| ja | Japanese |  |
| ko | Korean |  |
| pl | Polish |  |
| pt | Portuguese |  |
| pt_BR | Portuguese (Brazilian) |  |
| ru | Russian |  |
| sv | Swedish |  |
| tr | Turkish |  |
| uk | Ukranian |  |
| zh | Chinese (Simplified) |  |
| zh_TW | Chinese (Traditional) |  |



### sunshine_name



| Description | The name displayed by Moonlight. |
| --- | --- |
| Default | PC hostname |
| Example | @code{}
            sunshine_name = Sunshine
            @endcode |



### min_log_level



| Description | The minimum log level printed to standard out. |  |
| --- | --- | --- |
| Default | @code{}
            info
            @endcode |  |
| Example | @code{}
            min_log_level = info
            @endcode |  |
| Choices | verbose | All logging message.
            @attention{This may negatively affect streaming performance.} |
| debug | Debug log messages and higher.
            @attention{This may negatively affect streaming performance.} |  |
| info | Informational log messages and higher. |  |
| warning | Warning log messages and higher. |  |
| error | Error log messages and higher. |  |
| fatal | Only fatal log messages. |  |
| none | No log messages. |  |



### global_prep_cmd



| Description | A list of commands to be run before/after all applications.
            If any of the prep-commands fail, starting the application is aborted. |
| --- | --- |
| Default | @code{}
            []
            @endcode |
| Example | @code{}
            global_prep_cmd = [{"do":"nircmd.exe setdisplay 1280 720 32 144","elevated":true,"undo":"nircmd.exe setdisplay 2560 1440 32 144"}]
            @endcode |



### notify_pre_releases



| Description | Whether to be notified of new pre-release versions of Sunshine. |
| --- | --- |
| Default | @code{}
            disabled
            @endcode |
| Example | @code{}
            notify_pre_releases = disabled
            @endcode |



### system_tray



| Description | Show icon in system tray and display desktop notifications |
| --- | --- |
| Default | @code{}
            enabled
            @endcode |
| Example | @code{}
            system_tray = enabled
            @endcode |



## Input

### controller



| Description | Whether to allow controller input from the client. |
| --- | --- |
| Default | @code{}
            enabled
            @endcode |
| Example | @code{}
            controller = enabled
            @endcode |



### gamepad



| Description | The type of gamepad to emulate on the host. |  |
| --- | --- | --- |
| Default | @code{}
            auto
            @endcode |  |
| Example | @code{}
            gamepad = auto
            @endcode |  |
| Choices | ds4 | DualShock 4 controller (PS4)
            @note{This option applies to Windows only.} |
| ds5 | DualShock 5 controller (PS5)
            @note{This option applies to Linux only.} |  |
| switch | Switch Pro controller
            @note{This option applies to Linux only.} |  |
| x360 | Xbox 360 controller
            @note{This option applies to Windows only.} |  |
| xone | Xbox One controller
            @note{This option applies to Linux only.} |  |



### ds4_back_as_touchpad_click



| Description | Allow Select/Back inputs to also trigger DS4 touchpad click. Useful for clients looking to
            emulate touchpad click on Xinput devices.
            @hint{Only applies when gamepad is set to ds4 manually. Unused in other gamepad modes.} |
| --- | --- |
| Default | @code{}
            enabled
            @endcode |
| Example | @code{}
            ds4_back_as_touchpad_click = enabled
            @endcode |



### motion_as_ds4



| Description | If a client reports that a connected gamepad has motion sensor support, emulate it on the
            host as a DS4 controller.
            
            
            When disabled, motion sensors will not be taken into account during gamepad type selection.
            @hint{Only applies when gamepad is set to auto.} |
| --- | --- |
| Default | @code{}
            enabled
            @endcode |
| Example | @code{}
            motion_as_ds4 = enabled
            @endcode |



### touchpad_as_ds4



| Description | If a client reports that a connected gamepad has a touchpad, emulate it on the host
            as a DS4 controller.
            
            
            When disabled, touchpad presence will not be taken into account during gamepad type selection.
            @hint{Only applies when gamepad is set to auto.} |
| --- | --- |
| Default | @code{}
            enabled
            @endcode |
| Example | @code{}
            touchpad_as_ds4 = enabled
            @endcode |



### ds5_inputtino_randomize_mac



| Description | Randomize the MAC-Address for the generated virtual controller.
            @hint{Only applies on linux for gamepads created as PS5-style controllers} |
| --- | --- |
| Default | @code{}
            enabled
            @endcode |
| Example | @code{}
            ds5_inputtino_randomize_mac = enabled
            @endcode |



### back_button_timeout



| Description | If the Back/Select button is held down for the specified number of milliseconds,
            a Home/Guide button press is emulated.
            @tip{If back_button_timeout < 0, then the Home/Guide button will not be emulated.} |
| --- | --- |
| Default | @code{}
            -1
            @endcode |
| Example | @code{}
            back_button_timeout = 2000
            @endcode |



### keyboard



| Description | Whether to allow keyboard input from the client. |
| --- | --- |
| Default | @code{}
            enabled
            @endcode |
| Example | @code{}
            keyboard = enabled
            @endcode |



### key_repeat_delay



| Description | The initial delay, in milliseconds, before repeating keys. Controls how fast keys will
            repeat themselves. |
| --- | --- |
| Default | @code{}
            500
            @endcode |
| Example | @code{}
            key_repeat_delay = 500
            @endcode |



### key_repeat_frequency



| Description | How often keys repeat every second.
            @tip{This configurable option supports decimals.} |
| --- | --- |
| Default | @code{}
            24.9
            @endcode |
| Example | @code{}
            key_repeat_frequency = 24.9
            @endcode |



### always_send_scancodes



| Description | Sending scancodes enhances compatibility with games and apps but may result in incorrect keyboard input
            from certain clients that aren't using a US English keyboard layout.
            
            
            Enable if keyboard input is not working at all in certain applications.
            
            
            Disable if keys on the client are generating the wrong input on the host.
            @caution{Applies to Windows only.} |
| --- | --- |
| Default | @code{}
            enabled
            @endcode |
| Example | @code{}
            always_send_scancodes = enabled
            @endcode |



### key_rightalt_to_key_win



| Description | It may be possible that you cannot send the Windows Key from Moonlight directly. In those cases it may be useful to
            make Sunshine think the Right Alt key is the Windows key. |
| --- | --- |
| Default | @code{}
            disabled
            @endcode |
| Example | @code{}
            key_rightalt_to_key_win = enabled
            @endcode |



### mouse



| Description | Whether to allow mouse input from the client. |
| --- | --- |
| Default | @code{}
            enabled
            @endcode |
| Example | @code{}
            mouse = enabled
            @endcode |



### high_resolution_scrolling



| Description | When enabled, Sunshine will pass through high resolution scroll events from Moonlight clients.
            
            This can be useful to disable for older applications that scroll too fast with high resolution scroll
            events. |
| --- | --- |
| Default | @code{}
            enabled
            @endcode |
| Example | @code{}
            high_resolution_scrolling = enabled
            @endcode |



### native_pen_touch



| Description | When enabled, Sunshine will pass through native pen/touch events from Moonlight clients.
            
            This can be useful to disable for older applications without native pen/touch support. |
| --- | --- |
| Default | @code{}
            enabled
            @endcode |
| Example | @code{}
            native_pen_touch = enabled
            @endcode |



### keybindings



| Description | Sometimes it may be useful to map keybindings. Wayland won't allow clients to capture the Win Key
            for example.
            @tip{See [virtual key codes](https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes)}
            @hint{keybindings needs to have a multiple of two elements.}
            @note{This option is not available in the UI. A PR would be welcome.} |
| --- | --- |
| Default | @code{}
            [
              0x10, 0xA0,
              0x11, 0xA2,
              0x12, 0xA4
            ]
            @endcode |
| Example | @code{}
            keybindings = [
              0x10, 0xA0,
              0x11, 0xA2,
              0x12, 0xA4,
              0x4A, 0x4B
            ]
            @endcode |



## Audio/Video

### audio_sink



| Description | The name of the audio sink used for audio loopback.
            @tip{To find the name of the audio sink follow these instructions.
            
            
            **Linux + pulseaudio:**
            
            @code{}
            pacmd list-sinks   grep "name:"
            @endcode
            
            
            **Linux + pipewire:**
            
            @code{}
            pactl info   grep Source
            # in some causes you'd need to use the `Sink` device, if `Source` doesn't work, so try:
            pactl info   grep Sink
            @endcode
            
            
            **macOS:**
            
            Sunshine can only access microphones on macOS due to system limitations.
            To stream system audio use
            [Soundflower](https://github.com/mattingalls/Soundflower) or
            [BlackHole](https://github.com/ExistentialAudio/BlackHole).
            
            
            **Windows:**
            
            Enter the following command in command prompt or PowerShell.
            @code{}
            %ProgramFiles%\Sunshine\tools\audio-info.exe
            @endcode
            If you have multiple audio devices with identical names, use the Device ID instead.
            }
            @attention{If you want to mute the host speakers, use
            [virtual_sink](#virtual_sink) instead.} |
| --- | --- |
| Default | Sunshine will select the default audio device. |
| Example (Linux) | @code{}
            audio_sink = alsa_output.pci-0000_09_00.3.analog-stereo
            @endcode |
| Example (macOS) | @code{}
            audio_sink = BlackHole 2ch
            @endcode |
| Example (Windows) | @code{}
            audio_sink = Speakers (High Definition Audio Device)
            @endcode |



### virtual_sink



| Description | The audio device that's virtual, like Steam Streaming Speakers. This allows Sunshine to stream audio,
            while muting the speakers.
            @tip{See [audio_sink](#audio_sink)!}
            @tip{These are some options for virtual sound devices.
            * Stream Streaming Speakers (Linux, macOS, Windows)
              * Steam must be installed.
              * Enable [install_steam_audio_drivers](#install_steam_audio_drivers)
                or use Steam Remote Play at least once to install the drivers.
            * [Virtual Audio Cable](https://vb-audio.com/Cable) (macOS, Windows)
            } |
| --- | --- |
| Default | n/a |
| Example | @code{}
            virtual_sink = Steam Streaming Speakers
            @endcode |



### stream_audio



| Description | Whether to stream audio or not. Disabling this can be useful for streaming headless displays as second monitors. |
| --- | --- |
| Default | @code{}
            enabled
            @endcode |
| Example | @code{}
            stream_audio = disabled
            @endcode |



### install_steam_audio_drivers



| Description | Installs the Steam Streaming Speakers driver (if Steam is installed) to support surround sound and muting
            host audio.
            @note{This option is only supported on Windows.} |
| --- | --- |
| Default | @code{}
            enabled
            @endcode |
| Example | @code{}
            install_steam_audio_drivers = enabled
            @endcode |



### adapter_name



| Description | Select the video card you want to stream.
            @tip{To find the appropriate values follow these instructions.
            
            
            **Linux + VA-API:**
            
            Unlike with *amdvce* and *nvenc*, it doesn't matter if video encoding is done on a different GPU.
            @code{}
            ls /dev/dri/renderD*  # to find all devices capable of VAAPI
            # replace ``renderD129`` with the device from above to list the name and capabilities of the device
            vainfo --display drm --device /dev/dri/renderD129   \
              grep -E "((VAProfileH264High VAProfileHEVCMain VAProfileHEVCMain10).*VAEntrypointEncSlice) Driver version"
            @endcode
            To be supported by Sunshine, it needs to have at the very minimum:
            `VAProfileH264High   : VAEntrypointEncSlice`
            
            
            **Windows:**
            
            Enter the following command in command prompt or PowerShell.
            @code{}
            %ProgramFiles%\Sunshine\tools\dxgi-info.exe
            @endcode
            For hybrid graphics systems, DXGI reports the outputs are connected to whichever graphics
            adapter that the application is configured to use, so it's not a reliable indicator of how the
            display is physically connected.
            } |
| --- | --- |
| Default | Sunshine will select the default video card. |
| Example (Linux) | @code{}
            adapter_name = /dev/dri/renderD128
            @endcode |
| Example (Windows) | @code{}
            adapter_name = Radeon RX 580 Series
            @endcode |



### output_name



| Description | Select the display number you want to stream.
            @tip{To find the appropriate values follow these instructions.
            
            
            **Linux:**
            
            During Sunshine startup, you should see the list of detected displays:
            @code{}
            Info: Detecting displays
            Info: Detected display: DVI-D-0 (id: 0) connected: false
            Info: Detected display: HDMI-0 (id: 1) connected: true
            Info: Detected display: DP-0 (id: 2) connected: true
            Info: Detected display: DP-1 (id: 3) connected: false
            Info: Detected display: DVI-D-1 (id: 4) connected: false
            @endcode
            You need to use the id value inside the parenthesis, e.g. `1`.
            
            
            **macOS:**
            
            During Sunshine startup, you should see the list of detected displays:
            @code{}
            Info: Detecting displays
            Info: Detected display: Monitor-0 (id: 3) connected: true
            Info: Detected display: Monitor-1 (id: 2) connected: true
            @endcode
            You need to use the id value inside the parenthesis, e.g. `3`.
            
            
            **Windows:**
            
            During Sunshine startup, you should see the list of detected displays:
            @code{}
            Info: Currently available display devices:
            [
              {
                "device_id": "{64243705-4020-5895-b923-adc862c3457e}",
                "display_name": "",
                "friendly_name": "IDD HDR",
                "info": null
              },
              {
                "device_id": "{77f67f3e-754f-5d31-af64-ee037e18100a}",
                "display_name": "",
                "friendly_name": "SunshineHDR",
                "info": null
              },
              {
                "device_id": "{daeac860-f4db-5208-b1f5-cf59444fb768}",
                "display_name": "\\\\.\\DISPLAY1",
                "friendly_name": "ROG PG279Q",
                "info": {
                  "hdr_state": null,
                  "origin_point": {
                    "x": 0,
                    "y": 0
                  },
                  "primary": true,
                  "refresh_rate": {
                    "type": "rational",
                    "value": {
                      "denominator": 1000,
                      "numerator": 119998
                    }
                  },
                  "resolution": {
                    "height": 1440,
                    "width": 2560
                  },
                  "resolution_scale": {
                    "type": "rational",
                    "value": {
                      "denominator": 100,
                      "numerator": 100
                    }
                  }
                }
              }
            ]
            @endcode
            You need to use the `device_id` value.
            } |
| --- | --- |
| Default | Sunshine will select the default display. |
| Example (Linux) | @code{}
            output_name = 0
            @endcode |
| Example (macOS) | @code{}
            output_name = 3
            @endcode |
| Example (Windows) | @code{}
            output_name = {daeac860-f4db-5208-b1f5-cf59444fb768}
            @endcode |



### isolated_virtual_display_option



| Description | Isolates the virtual display.
            @note{Applies to Windows only.} |
| --- | --- |
| Default | @code{}disabled@endcode |
| enabled | Change the position of the virtual display (and other displays if there is a hole) |




### dd_configuration_option



| Description | Perform mandatory verification and additional configuration for the display device.
            @note{Applies to Windows only.} |  |
| --- | --- | --- |
| Default | @code{}
            disabled
            @endcode |  |
| Example | @code{}
            dd_configuration_option = ensure_only_display
            @endcode |  |
| Choices | disabled | Perform no additional configuration (disables all `dd_` configuration options). |
| verify_only | Verify that display is active only (this is a mandatory step without any extra steps to verify display state). |  |
| ensure_active | Activate the display if it's currently inactive. |  |
| ensure_primary | Activate the display if it's currently inactive and make it primary. |  |
| ensure_only_display | Activate the display if it's currently inactive and disable all others. |  |



### dd_resolution_option



| Description | Perform additional resolution configuration for the display device.
            @note{"Optimize game settings" must be enabled in Moonlight for this option to work.}
            @note{Applies to Windows only.} |  |
| --- | --- | --- |
| Default | @code{}auto@endcode |  |
| Example | @code{}
            dd_resolution_option = manual
            @endcode |  |
| Choices | disabled | Perform no additional configuration. |
| auto | Change resolution to the requested resolution from the client. |  |
| manual | Change resolution to the user specified one (set via [dd_manual_resolution](#dd_manual_resolution)). |  |



### dd_manual_resolution



| Description | Specify manual resolution to be used.
            @note{[dd_resolution_option](#dd_resolution_option) must be set to `manual`}
            @note{Applies to Windows only.} |
| --- | --- |
| Default | n/a |
| Example | @code{}
            dd_manual_resolution = 1920x1080
            @endcode |



### dd_refresh_rate_option



| Description | Perform additional refresh rate configuration for the display device.
            @note{Applies to Windows only.} |  |
| --- | --- | --- |
| Default | @code{}auto@endcode |  |
| Example | @code{}
            dd_refresh_rate_option = manual
            @endcode |  |
| Choices | disabled | Perform no additional configuration. |
| auto | Change refresh rate to the requested FPS value from the client. |  |
| manual | Change refresh rate to the user specified one (set via [dd_manual_refresh_rate](#dd_manual_refresh_rate)). |  |



### dd_manual_refresh_rate



| Description | Specify manual refresh rate to be used.
            @note{[dd_refresh_rate_option](#dd_refresh_rate_option) must be set to `manual`}
            @note{Applies to Windows only.} |
| --- | --- |
| Default | n/a |
| Example | @code{}
            dd_manual_resolution = 120
            dd_manual_resolution = 59.95
            @endcode |



### dd_hdr_option



| Description | Perform additional HDR configuration for the display device.
            @note{Applies to Windows only.} |  |
| --- | --- | --- |
| Default | @code{}auto@endcode |  |
| Example | @code{}
            dd_hdr_option = disabled
            @endcode |  |
| Choices | disabled | Perform no additional configuration. |
| auto | Change HDR to the requested state from the client if the display supports it. |  |



### dd_wa_hdr_toggle_delay



| Description | When using virtual display device (VDD) for streaming, it might incorrectly display HDR color. Sunshine can try to mitigate this issue, by turning HDR off and then on again.
            If the value is set to 0, the workaround is disabled (default). If the value is between 0 and 3000 milliseconds, Sunshine will turn off HDR, wait for the specified amount of time and then turn HDR on again. The recommended delay time is around 500 milliseconds in most cases.
            DO NOT use this workaround unless you actually have issues with HDR as it directly impacts stream start time!
            @note{This option works independently of [dd_hdr_option](#dd_hdr_option)}
            @note{Applies to Windows only.} |
| --- | --- |
| Default | @code{}
            0
            @endcode |
| Example | @code{}
            dd_wa_hdr_toggle_delay = 500
            @endcode |



### dd_config_revert_delay



| Description | Additional delay in milliseconds to wait before reverting configuration when the app has been closed or the last session terminated.
            Main purpose is to provide a smoother transition when quickly switching between apps.
            @note{Applies to Windows only.} |
| --- | --- |
| Default | @code{}3000@endcode |
| Example | @code{}
            dd_config_revert_delay = 1500
            @endcode |




### dd_config_revert_on_disconnect



| Description | When enabled, display configuration is reverted upon disconnect of all clients instead of app close or last session termination.
            This can be useful for returning to physical usage of the host machine without closing the active app.
            @warning{Some applications may not function properly when display configuration is changed while active.}
            @note{Applies to Windows only.} |
| --- | --- |
| Default | @code{}disabled@endcode |
| Example | @code{}
            dd_config_revert_on_disconnect = enabled
            @endcode |



### dd_mode_remapping



| Description | Remap the requested resolution and FPS to another display mode.
            Depending on the [dd_resolution_option](#dd_resolution_option) and
            [dd_refresh_rate_option](#dd_refresh_rate_option) values, the following mapping
            groups are available:
            
                `mixed` - both options are set to `auto`.
                
                  `resolution_only` - only [dd_resolution_option](#dd_resolution_option) is set to `auto`.
                
                
                  `refresh_rate_only` - only [dd_refresh_rate_option](#dd_refresh_rate_option) is set to `auto`.
                
            
            For each of those groups, a list of fields can be configured to perform remapping:
            
                
                  `requested_resolution` - resolution that needs to be matched in order to use this remapping entry.
                
                `requested_fps` - FPS that needs to be matched in order to use this remapping entry.
                `final_resolution` - resolution value to be used if the entry was matched.
                `final_refresh_rate` - refresh rate value to be used if the entry was matched.
            
            If `requested_*` field is left empty, it will match **everything**.
            If `final_*` field is left empty, the original value will not be remapped and either a requested, manual
            or current value is used. However, at least one `final_*` must be set, otherwise the entry is considered
            invalid.
            @note{"Optimize game settings" must be enabled on client side for ANY entry with `resolution`
            field to be considered.}
            @note{First entry to be matched in the list is the one that will be used.}
            @tip{`requested_resolution` and `final_resolution` can be omitted for `refresh_rate_only` group.}
            @tip{`requested_fps` and `final_refresh_rate` can be omitted for `resolution_only` group.}
            @note{Applies to Windows only.} |
| --- | --- |
| Default | @code{}
            dd_mode_remapping = {
              "mixed": [],
              "resolution_only": [],
              "refresh_rate_only": []
            }
            @endcode |
| Example | @code{}
            dd_mode_remapping = {
              "mixed": [
                {
                  "requested_fps": "60",
                  "final_refresh_rate": "119.95",
                  "requested_resolution": "1920x1080",
                  "final_resolution": "2560x1440"
                },
                {
                  "requested_fps": "60",
                  "final_refresh_rate": "120",
                  "requested_resolution": "",
                  "final_resolution": ""
                }
              ],
              "resolution_only": [
                {
                  "requested_resolution": "1920x1080",
                  "final_resolution": "2560x1440"
                }
              ],
              "refresh_rate_only": [
                {
                  "requested_fps": "60",
                  "final_refresh_rate": "119.95"
                }
              ]
            }@endcode |



### max_bitrate



| Description | The maximum bitrate (in Kbps) that Sunshine will encode the stream at. If set to 0, it will always use the bitrate requested by Moonlight. |
| --- | --- |
| Default | @code{}
            0
            @endcode |
| Example | @code{}
            max_bitrate = 5000
            @endcode |



### minimum_fps_target



| Description | Sunshine tries to save bandwidth when content on screen is static or a low framerate. Because many clients expect a constant stream of video frames, a certain amount of duplicate frames are sent when this happens. This setting controls the lowest effective framerate a stream can reach. |  |
| --- | --- | --- |
| Default | @code{}
            0
            @endcode |  |
| Choices | 0 | Use half the stream's FPS as the minimum target. |
| 1-1000 | Specify your own value. The real minimum may differ from this value. |  |



## Network

### upnp



| Description | Sunshine will attempt to open ports for streaming over the internet. |
| --- | --- |
| Default | @code{}
            disabled
            @endcode |
| Example | @code{}
            upnp = enabled
            @endcode |



### address_family



| Description | Set the address family that Sunshine will use. |  |
| --- | --- | --- |
| Default | @code{}
            ipv4
            @endcode |  |
| Example | @code{}
            address_family = both
            @endcode |  |
| Choices | ipv4 | IPv4 only |
| both | IPv4+IPv6 |  |



### port



| Description | Set the family of ports used by Sunshine.
            Changing this value will offset other ports as shown in config UI. |
| --- | --- |
| Default | @code{}
            47989
            @endcode |
| Range | 1029-65514 |
| Example | @code{}
            port = 47989
            @endcode |



### origin_web_ui_allowed



| Description | The origin of the remote endpoint address that is not denied for HTTPS Web UI. |  |
| --- | --- | --- |
| Default | @code{}
            lan
            @endcode |  |
| Example | @code{}
            origin_web_ui_allowed = lan
            @endcode |  |
| Choices | pc | Only localhost may access the web ui |
| lan | Only LAN devices may access the web ui |  |
| wan | Anyone may access the web ui |  |



### external_ip



| Description | If no external IP address is given, Sunshine will attempt to automatically detect external ip-address. |
| --- | --- |
| Default | Automatic |
| Example | @code{}
            external_ip = 123.456.789.12
            @endcode |



### lan_encryption_mode



| Description | This determines when encryption will be used when streaming over your local network.
            @warning{Encryption can reduce streaming performance, particularly on less powerful hosts and clients.} |  |
| --- | --- | --- |
| Default | @code{}
            0
            @endcode |  |
| Example | @code{}
            lan_encryption_mode = 0
            @endcode |  |
| Choices | 0 | encryption will not be used |
| 1 | encryption will be used if the client supports it |  |
| 2 | encryption is mandatory and unencrypted connections are rejected |  |



### wan_encryption_mode



| Description | This determines when encryption will be used when streaming over the Internet.
            @warning{Encryption can reduce streaming performance, particularly on less powerful hosts and clients.} |  |
| --- | --- | --- |
| Default | @code{}
            1
            @endcode |  |
| Example | @code{}
            wan_encryption_mode = 1
            @endcode |  |
| Choices | 0 | encryption will not be used |
| 1 | encryption will be used if the client supports it |  |
| 2 | encryption is mandatory and unencrypted connections are rejected |  |



### ping_timeout



| Description | How long to wait, in milliseconds, for data from Moonlight before shutting down the stream. |
| --- | --- |
| Default | @code{}
            10000
            @endcode |
| Example | @code{}
            ping_timeout = 10000
            @endcode |



## Config Files

### file_apps



| Description | The application configuration file path. The file contains a JSON formatted list of applications that
            can be started by Moonlight. |
| --- | --- |
| Default | @code{}
            apps.json
            @endcode |
| Example | @code{}
            file_apps = apps.json
            @endcode |



### credentials_file



| Description | The file where user credentials for the UI are stored. |
| --- | --- |
| Default | @code{}
            sunshine_state.json
            @endcode |
| Example | @code{}
            credentials_file = sunshine_state.json
            @endcode |



### log_path



| Description | The path where the Sunshine log is stored. |
| --- | --- |
| Default | @code{}
            sunshine.log
            @endcode |
| Example | @code{}
            log_path = sunshine.log
            @endcode |



### pkey



| Description | The private key used for the web UI and Moonlight client pairing. For best compatibility,
            this should be an RSA-2048 private key.
            @warning{Not all Moonlight clients support ECDSA keys or RSA key lengths other than 2048 bits.} |
| --- | --- |
| Default | @code{}
            credentials/cakey.pem
            @endcode |
| Example | @code{}
            pkey = /dir/pkey.pem
            @endcode |



### cert



| Description | The certificate used for the web UI and Moonlight client pairing. For best compatibility,
            this should have an RSA-2048 public key.
            @warning{Not all Moonlight clients support ECDSA keys or RSA key lengths other than 2048 bits.} |
| --- | --- |
| Default | @code{}
            credentials/cacert.pem
            @endcode |
| Example | @code{}
            cert = /dir/cert.pem
            @endcode |



### file_state



| Description | The file where current state of Sunshine is stored. |
| --- | --- |
| Default | @code{}
            sunshine_state.json
            @endcode |
| Example | @code{}
            file_state = sunshine_state.json
            @endcode |



## Advanced

### fec_percentage



| Description | Percentage of error correcting packets per data packet in each video frame.
            @warning{Higher values can correct for more network packet loss,
            but at the cost of increasing bandwidth usage.} |
| --- | --- |
| Default | @code{}
            20
            @endcode |
| Range | 1-255 |
| Example | @code{}
            fec_percentage = 20
            @endcode |



### qp



| Description | Quantization Parameter. Some devices don't support Constant Bit Rate. For those devices, QP is used instead.
            @warning{Higher value means more compression, but less quality.} |
| --- | --- |
| Default | @code{}
            28
            @endcode |
| Example | @code{}
            qp = 28
            @endcode |



### min_threads



| Description | Minimum number of CPU threads used for encoding.
            @note{Increasing the value slightly reduces encoding efficiency, but the tradeoff is usually worth it to
            gain the use of more CPU cores for encoding. The ideal value is the lowest value that can reliably encode
            at your desired streaming settings on your hardware.} |
| --- | --- |
| Default | @code{}
            2
            @endcode |
| Example | @code{}
            min_threads = 2
            @endcode |



### hevc_mode



| Description | Allows the client to request HEVC Main or HEVC Main10 video streams.
            @warning{HEVC is more CPU-intensive to encode, so enabling this may reduce performance when using software
            encoding.} |  |
| --- | --- | --- |
| Default | @code{}
            0
            @endcode |  |
| Example | @code{}
            hevc_mode = 2
            @endcode |  |
| Choices | 0 | advertise support for HEVC based on encoder capabilities (recommended) |
| 1 | do not advertise support for HEVC |  |
| 2 | advertise support for HEVC Main profile |  |
| 3 | advertise support for HEVC Main and Main10 (HDR) profiles |  |



### av1_mode



| Description | Allows the client to request AV1 Main 8-bit or 10-bit video streams.
            @warning{AV1 is more CPU-intensive to encode, so enabling this may reduce performance when using software
            encoding.} |  |
| --- | --- | --- |
| Default | @code{}
            0
            @endcode |  |
| Example | @code{}
            av1_mode = 2
            @endcode |  |
| Choices | 0 | advertise support for AV1 based on encoder capabilities (recommended) |
| 1 | do not advertise support for AV1 |  |
| 2 | advertise support for AV1 Main 8-bit profile |  |
| 3 | advertise support for AV1 Main 8-bit and 10-bit (HDR) profiles |  |



### capture



| Description | Force specific screen capture method. |  |
| --- | --- | --- |
| Default | Automatic.
            Sunshine will use the first capture method available in the order of the table above. |  |
| Example | @code{}
            capture = kms
            @endcode |  |
| Choices | nvfbc | Use NVIDIA Frame Buffer Capture to capture direct to GPU memory. This is usually the fastest method for
            NVIDIA cards. NvFBC does not have native Wayland support and does not work with XWayland.
            @note{Applies to Linux only.} |
| wlr | Capture for wlroots based Wayland compositors via wlr-screencopy-unstable-v1. It is possible to capture
            virtual displays in e.g. Hyprland using this method.
            @note{Applies to Linux only.} |  |
| kms | DRM/KMS screen capture from the kernel. This requires that Sunshine has `cap_sys_admin` capability.
            @note{Applies to Linux only.} |  |
| x11 | Uses XCB. This is the slowest and most CPU intensive so should be avoided if possible.
            @note{Applies to Linux only.} |  |
| ddx | Use DirectX Desktop Duplication API to capture the display. This is well-supported on Windows machines.
            @note{Applies to Windows only.} |  |
| wgc | (beta feature) Use Windows.Graphics.Capture to capture the display.
            @note{Applies to Windows only.}
            @attention{This capture method is not compatible with the Sunshine service.} |  |



### encoder



| Description | Force a specific encoder. |  |
| --- | --- | --- |
| Default | Sunshine will use the first encoder that is available. |  |
| Example | @code{}
            encoder = nvenc
            @endcode |  |
| Choices | nvenc | For NVIDIA graphics cards |
| quicksync | For Intel graphics cards |  |
| amdvce | For AMD graphics cards |  |
| vaapi | Use Linux VA-API (AMD, Intel) |  |
| software | Encoding occurs on the CPU |  |



## NVIDIA NVENC Encoder

### nvenc_preset



| Description | NVENC encoder performance preset.
            Higher numbers improve compression (quality at given bitrate) at the cost of increased encoding latency.
            Recommended to change only when limited by network or decoder, otherwise similar effect can be accomplished
            by increasing bitrate.
            @note{This option only applies when using NVENC [encoder](#encoder).} |  |
| --- | --- | --- |
| Default | @code{}
            1
            @endcode |  |
| Example | @code{}
            nvenc_preset = 1
            @endcode |  |
| Choices | 1 | P1 (fastest) |
| 2 | P2 |  |
| 3 | P3 |  |
| 4 | P4 |  |
| 5 | P5 |  |
| 6 | P6 |  |
| 7 | P7 (slowest) |  |



### nvenc_twopass



| Description | Enable two-pass mode in NVENC encoder.
            This allows to detect more motion vectors, better distribute bitrate across the frame and more strictly
            adhere to bitrate limits. Disabling it is not recommended since this can lead to occasional bitrate
            overshoot and subsequent packet loss.
            @note{This option only applies when using NVENC [encoder](#encoder).} |  |
| --- | --- | --- |
| Default | @code{}
            quarter_res
            @endcode |  |
| Example | @code{}
            nvenc_twopass = quarter_res
            @endcode |  |
| Choices | disabled | One pass (fastest) |
| quarter_res | Two passes, first pass at quarter resolution (faster) |  |
| full_res | Two passes, first pass at full resolution (slower) |  |



### nvenc_spatial_aq



| Description | Assign higher QP values to flat regions of the video.
            Recommended to enable when streaming at lower bitrates.
            @note{This option only applies when using NVENC [encoder](#encoder).}
            @warning{Enabling this option may reduce performance.} |
| --- | --- |
| Default | @code{}
            disabled
            @endcode |
| Example | @code{}
            nvenc_spatial_aq = disabled
            @endcode |



### nvenc_vbv_increase



| Description | Single-frame VBV/HRD percentage increase.
            By default Sunshine uses single-frame VBV/HRD, which means any encoded video frame size is not expected to
            exceed requested bitrate divided by requested frame rate. Relaxing this restriction can be beneficial and
            act as low-latency variable bitrate, but may also lead to packet loss if the network doesn't have buffer
            headroom to handle bitrate spikes. Maximum accepted value is 400, which corresponds to 5x increased
            encoded video frame upper size limit.
            @note{This option only applies when using NVENC [encoder](#encoder).}
            @warning{Can lead to network packet loss.} |
| --- | --- |
| Default | @code{}
            0
            @endcode |
| Range | 0-400 |
| Example | @code{}
            nvenc_vbv_increase = 0
            @endcode |



### nvenc_realtime_hags



| Description | Use realtime gpu scheduling priority in NVENC when hardware accelerated gpu scheduling (HAGS) is enabled
            in Windows. Currently, NVIDIA drivers may freeze in encoder when HAGS is enabled, realtime priority is used
            and VRAM utilization is close to maximum. Disabling this option lowers the priority to high, sidestepping
            the freeze at the cost of reduced capture performance when the GPU is heavily loaded.
            @note{This option only applies when using NVENC [encoder](#encoder).}
            @note{Applies to Windows only.} |
| --- | --- |
| Default | @code{}
            enabled
            @endcode |
| Example | @code{}
            nvenc_realtime_hags = enabled
            @endcode |



### nvenc_latency_over_power



| Description | Adaptive P-State algorithm which NVIDIA drivers employ doesn't work well with low latency streaming,
            so Sunshine requests high power mode explicitly.
            @note{This option only applies when using NVENC [encoder](#encoder).}
            @warning{Disabling this is not recommended since this can lead to significantly increased encoding latency.}
            @note{Applies to Windows only.} |
| --- | --- |
| Default | @code{}
            enabled
            @endcode |
| Example | @code{}
            nvenc_latency_over_power = enabled
            @endcode |



### nvenc_opengl_vulkan_on_dxgi



| Description | Sunshine can't capture fullscreen OpenGL and Vulkan programs at full frame rate unless they present on
            top of DXGI. With this option enabled Sunshine changes global Vulkan/OpenGL present method to
            "Prefer layered on DXGI Swapchain". This is system-wide setting that is reverted on Sunshine program exit.
            @note{This option only applies when using NVENC [encoder](#encoder).}
            @note{Applies to Windows only.} |
| --- | --- |
| Default | @code{}
            enabled
            @endcode |
| Example | @code{}
            nvenc_opengl_vulkan_on_dxgi = enabled
            @endcode |



### nvenc_h264_cavlc



| Description | Prefer CAVLC entropy coding over CABAC in H.264 when using NVENC.
            CAVLC is outdated and needs around 10% more bitrate for same quality, but provides slightly faster
            decoding when using software decoder.
            @note{This option only applies when using H.264 format with the
            NVENC [encoder](#encoder).} |
| --- | --- |
| Default | @code{}
            disabled
            @endcode |
| Example | @code{}
            nvenc_h264_cavlc = disabled
            @endcode |



## Intel QuickSync Encoder

### qsv_preset



| Description | The encoder preset to use.
            @note{This option only applies when using quicksync [encoder](#encoder).} |  |
| --- | --- | --- |
| Default | @code{}
            medium
            @endcode |  |
| Example | @code{}
            qsv_preset = medium
            @endcode |  |
| Choices | veryfast | fastest (lowest quality) |
| faster | faster (lower quality) |  |
| fast | fast (low quality) |  |
| medium | medium (default) |  |
| slow | slow (good quality) |  |
| slower | slower (better quality) |  |
| veryslow | slowest (best quality) |  |



### qsv_coder



| Description | The entropy encoding to use.
            @note{This option only applies when using H.264 with the quicksync
            [encoder](#encoder).} |  |
| --- | --- | --- |
| Default | @code{}
            auto
            @endcode |  |
| Example | @code{}
            qsv_coder = auto
            @endcode |  |
| Choices | auto | let ffmpeg decide |
| cabac | context adaptive binary arithmetic coding - higher quality |  |
| cavlc | context adaptive variable-length coding - faster decode |  |



### qsv_slow_hevc



| Description | This options enables use of HEVC on older Intel GPUs that only support low power encoding for H.264.
            @note{This option only applies when using quicksync [encoder](#encoder).}
            @caution{Streaming performance may be significantly reduced when this option is enabled.} |
| --- | --- |
| Default | @code{}
            disabled
            @endcode |
| Example | @code{}
            qsv_slow_hevc = disabled
            @endcode |



## AMD AMF Encoder

### amd_usage



| Description | The encoder usage profile is used to set the base set of encoding parameters.
            @note{This option only applies when using amdvce [encoder](#encoder).}
            @note{The other AMF options that follow will override a subset of the settings applied by your usage
            profile, but there are hidden parameters set in usage profiles that cannot be overridden elsewhere.} |  |
| --- | --- | --- |
| Default | @code{}
            ultralowlatency
            @endcode |  |
| Example | @code{}
            amd_usage = ultralowlatency
            @endcode |  |
| Choices | transcoding | transcoding (slowest) |
| webcam | webcam (slow) |  |
| lowlatency_high_quality | low latency, high quality (fast) |  |
| lowlatency | low latency (faster) |  |
| ultralowlatency | ultra low latency (fastest) |  |



### amd_rc



| Description | The encoder rate control.
            @note{This option only applies when using amdvce [encoder](#encoder).}
            @warning{The `vbr_latency` option generally works best, but some bitrate overshoots may still occur.
            Enabling HRD allows all bitrate based rate controls to better constrain peak bitrate, but may result in
            encoding artifacts depending on your card.} |  |
| --- | --- | --- |
| Default | @code{}
            vbr_latency
            @endcode |  |
| Example | @code{}
            amd_rc = vbr_latency
            @endcode |  |
| Choices | cqp | constant qp mode |
| cbr | constant bitrate |  |
| vbr_latency | variable bitrate, latency constrained |  |
| vbr_peak | variable bitrate, peak constrained |  |



### amd_enforce_hrd



| Description | Enable Hypothetical Reference Decoder (HRD) enforcement to help constrain the target bitrate.
            @note{This option only applies when using amdvce [encoder](#encoder).}
            @warning{HRD is known to cause encoding artifacts or negatively affect encoding quality on certain cards.} |
| --- | --- |
| Default | @code{}
            disabled
            @endcode |
| Example | @code{}
            amd_enforce_hrd = disabled
            @endcode |



### amd_quality



| Description | The quality profile controls the tradeoff between speed and quality of encoding.
            @note{This option only applies when using amdvce [encoder](#encoder).} |  |
| --- | --- | --- |
| Default | @code{}
            balanced
            @endcode |  |
| Example | @code{}
            amd_quality = balanced
            @endcode |  |
| Choices | speed | prefer speed |
| balanced | balanced |  |
| quality | prefer quality |  |



### amd_preanalysis



| Description | Preanalysis can increase encoding quality at the cost of latency.
            @note{This option only applies when using amdvce [encoder](#encoder).} |
| --- | --- |
| Default | @code{}
            disabled
            @endcode |
| Example | @code{}
            amd_preanalysis = disabled
            @endcode |



### amd_vbaq



| Description | Variance Based Adaptive Quantization (VBAQ) can increase subjective visual quality by prioritizing
            allocation of more bits to smooth areas compared to more textured areas.
            @note{This option only applies when using amdvce [encoder](#encoder).} |
| --- | --- |
| Default | @code{}
            enabled
            @endcode |
| Example | @code{}
            amd_vbaq = enabled
            @endcode |



### amd_coder



| Description | The entropy encoding to use.
            @note{This option only applies when using H.264 with the amdvce
            [encoder](#encoder).} |  |
| --- | --- | --- |
| Default | @code{}
            auto
            @endcode |  |
| Example | @code{}
            amd_coder = auto
            @endcode |  |
| Choices | auto | let ffmpeg decide |
| cabac | context adaptive binary arithmetic coding - faster decode |  |
| cavlc | context adaptive variable-length coding - higher quality |  |



## VideoToolbox Encoder

### vt_coder



| Description | The entropy encoding to use.
            @note{This option only applies when using macOS.} |  |
| --- | --- | --- |
| Default | @code{}
            auto
            @endcode |  |
| Example | @code{}
            vt_coder = auto
            @endcode |  |
| Choices | auto | let ffmpeg decide |
| cabac | context adaptive binary arithmetic coding - faster decode |  |
| cavlc | context adaptive variable-length coding - higher quality |  |



### vt_software



| Description | Force Video Toolbox to use software encoding.
            @note{This option only applies when using macOS.} |  |
| --- | --- | --- |
| Default | @code{}
            auto
            @endcode |  |
| Example | @code{}
            vt_software = auto
            @endcode |  |
| Choices | auto | let ffmpeg decide |
| disabled | disable software encoding |  |
| allowed | allow software encoding |  |
| forced | force software encoding |  |



### vt_realtime



| Description | Realtime encoding.
            @note{This option only applies when using macOS.}
            @warning{Disabling realtime encoding might result in a delayed frame encoding or frame drop.} |
| --- | --- |
| Default | @code{}
            enabled
            @endcode |
| Example | @code{}
            vt_realtime = enabled
            @endcode |



## VA-API Encoder

### vaapi_strict_rc_buffer



| Description | Enabling this option can avoid dropped frames over the network during scene changes, but video quality may
            be reduced during motion.
            @note{This option only applies for H.264 and HEVC when using VA-API [encoder](#encoder) on AMD GPUs.} |
| --- | --- |
| Default | @code{}
            disabled
            @endcode |
| Example | @code{}
            vaapi_strict_rc_buffer = enabled
            @endcode |



## Software Encoder

### sw_preset



| Description | The encoder preset to use.
            @note{This option only applies when using software [encoder](#encoder).}
            @note{From [FFmpeg](https://trac.ffmpeg.org/wiki/Encode/H.264#preset).
            
            
            A preset is a collection of options that will provide a certain encoding speed to compression ratio. A slower
            preset will provide better compression (compression is quality per filesize). This means that, for example, if
            you target a certain file size or constant bit rate, you will achieve better quality with a slower preset.
            Similarly, for constant quality encoding, you will simply save bitrate by choosing a slower preset.
            
            
            Use the slowest preset that you have patience for.} |  |
| --- | --- | --- |
| Default | @code{}
            superfast
            @endcode |  |
| Example | @code{}
            sw_preset = superfast
            @endcode |  |
| Choices | ultrafast | fastest |
| superfast |  |  |
| veryfast |  |  |
| faster |  |  |
| fast |  |  |
| medium |  |  |
| slow |  |  |
| slower |  |  |
| veryslow | slowest |  |



### sw_tune



| Description | The tuning preset to use.
            @note{This option only applies when using software [encoder](#encoder).}
            @note{From [FFmpeg](https://trac.ffmpeg.org/wiki/Encode/H.264#preset).
            
            
            You can optionally use -tune to change settings based upon the specifics of your input.
            } |  |
| --- | --- | --- |
| Default | @code{}
            zerolatency
            @endcode |  |
| Example | @code{}
            sw_tune = zerolatency
            @endcode |  |
| Choices | film | use for high quality movie content; lowers deblocking |
| animation | good for cartoons; uses higher deblocking and more reference frames |  |
| grain | preserves the grain structure in old, grainy film material |  |
| stillimage | good for slideshow-like content |  |
| fastdecode | allows faster decoding by disabling certain filters |  |
| zerolatency | good for fast encoding and low-latency streaming |  |





| Previous          |                            Next |
|:------------------|--------------------------------:|
| [Legal](legal.md) | [App Examples](app_examples.md) |




  
  [TOC]

---

## File: docs/contributing.md

# Contributing
Read our contribution guide in our organization level
[docs](https://docs.lizardbyte.dev/latest/developers/contributing.html).

## Recommended Tools

| Tool                                                                                                                                                                           | Description                                                                                                                                                                           |
|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------|
| [](https://www.jetbrains.com/clion/)CLion | Recommended IDE for C and C++ development. Free for non-commercial use. |

## Project Patterns

### Web UI
* The Web UI uses [Vite](https://vitejs.dev) as its build system.
* The HTML pages used by the Web UI are found in `./src_assets/common/assets/web`.
* [EJS](https://www.npmjs.com/package/vite-plugin-ejs) is used as a templating system for the pages
  (check `template_header.html` and `template_header_main.html`).
* The Style System is provided by [Bootstrap](https://getbootstrap.com).
* The JS framework used by the more interactive pages is [Vue.js](https://vuejs.org).

#### Building

@tabs{
  @tab{CMake | ```bash
    cmake -B build -G Ninja -S . --target web-ui
    ninja -C build web-ui
    ```}
  @tab{Manual | ```bash
    npm run dev
    ```}
}

### Localization
Sunshine and related LizardByte projects are being localized into various languages.
The default language is `en` (English).



@admonition{Community | We are looking for language coordinators to help approve translations.
The goal is to have the bars above filled with green!
If you are interesting, please reach out to us on our Discord server.}

#### CrowdIn
The translations occur on [CrowdIn][crowdin-url].
Anyone is free to contribute to the localization there.

##### Translation Basics
* The brand names *LizardByte* and *Sunshine* should never be translated.
* Other brand names should never be translated. Examples include *AMD*, *Intel*, and *NVIDIA*.

##### CrowdIn Integration
How does it work?

When a change is made to Sunshine source code, a workflow generates new translation templates
that get pushed to CrowdIn automatically.

When translations are updated on CrowdIn, a push gets made to the *l10n_master* branch and a PR is made against the
*master* branch. Once the PR is merged, all updated translations are part of the project and will be included in the
next release.

#### Extraction

##### Web UI
Sunshine uses [Vue I18n](https://vue-i18n.intlify.dev) for localizing the UI.
The following is a simple example of how to use it.

* Add the string to the `./src_assets/common/assets/web/public/assets/locale/en.json` file, in English.
  ```json
  {
   "index": {
     "welcome": "Hello, Sunshine!"
   }
  }
  ```

  > [!NOTE]
  > The JSON keys should be sorted alphabetically. You can use [jsonabc](https://novicelab.org/jsonabc)
  > to sort the keys.

  > [!IMPORTANT]
  > Due to the integration with Crowdin, it is important to only add strings to the *en.json* file,
  > and to not modify any other language files. After the PR is merged, the translations can take place
  > on [CrowdIn][crowdin-url]. Once the translations are complete, a PR will be made
  > to merge the translations into Sunshine.

* Use the string in the Vue component.
  ```html
  <template>
    
      {{ $t('index.welcome') }}
    
  </template>
  ```

  > [!TIP]
  > More formatting examples can be found in the
  > [Vue I18n guide](https://kazupon.github.io/vue-i18n/guide/formatting.html).

##### C++

There should be minimal cases where strings need to be extracted from C++ source code; however it may be necessary in
some situations. For example the system tray icon could be localized as it is user interfacing.

* Wrap the string to be extracted in a function as shown.
  ```cpp
  #include 
  #include <string>

  std::string msg = boost::locale::translate("Hello world!");
  ```

> [!TIP]
> More examples can be found in the documentation for
> [boost locale](https://www.boost.org/doc/libs/1_70_0/libs/locale/doc/html/messages_formatting.html).

> [!WARNING]
> The below is for information only. Contributors should never include manually updated template files, or
> manually compiled language files in Pull Requests.

Strings are automatically extracted from the code to the `locale/sunshine.po` template file. The generated file is
used by CrowdIn to generate language specific template files. The file is generated using the
`.github/workflows/localize.yml` workflow and is run on any push event into the `master` branch. Jobs are only run if
any of the following paths are modified.

```yaml
- 'src/**'
```

When testing locally it may be desirable to manually extract, initialize, update, and compile strings. Python is
required for this, along with the python dependencies in the `./scripts/requirements.txt` file. Additionally,
[xgettext](https://www.gnu.org/software/gettext) must be installed.

* Extract, initialize, and update
  ```bash
  python ./scripts/_locale.py --extract --init --update
  ```

* Compile
  ```bash
  python ./scripts/_locale.py --compile
  ```

> [!IMPORTANT]
> Due to the integration with CrowdIn, it is important to not include any extracted or compiled files in
> Pull Requests. The files are automatically generated and updated by the workflow. Once the PR is merged, the
> translations can take place on [CrowdIn][crowdin-url]. Once the translations are
> complete, a PR will be made to merge the translations into Sunshine.

### Testing

#### Clang Format
Source code is tested against the `.clang-format` file for linting errors. The workflow file responsible for clang
format testing is `.github/workflows/cpp-clang-format-lint.yml`.

Option 1:
```bash
find ./ -iname *.cpp -o -iname *.h -iname *.m -iname *.mm | xargs clang-format -i
```

Option 2 (will modify files):
```bash
python ./scripts/update_clang_format.py
```

#### Unit Testing
Sunshine uses [Google Test](https://github.com/google/googletest) for unit testing. Google Test is included in the
repo as a submodule. The test sources are located in the `./tests` directory.

The tests need to be compiled into an executable, and then run. The tests are built using the normal build process, but
can be disabled by setting the `BUILD_TESTS` CMake option to `OFF`.

To run the tests, execute the following command.

```bash
./build/tests/test_sunshine
```

To see all available options, run the tests with the `--help` flag.

```bash
./build/tests/test_sunshine --help
```

> [!TIP]
> See the googletest [FAQ](https://google.github.io/googletest/faq.html) for more information on how to use Google Test.

We use [gcovr](https://www.gcovr.com) to generate code coverage reports,
and [Codecov](https://about.codecov.io) to analyze the reports for all PRs and commits.

Codecov will fail a PR if the total coverage is reduced too much, or if not enough of the diff is covered by tests.
In some cases, the code cannot be covered when running the tests inside of GitHub runners. For example, any test that
needs access to the GPU will not be able to run. In these cases, the coverage can be omitted by adding comments to the
code. See the [gcovr documentation](https://gcovr.com/en/stable/guide/exclusion-markers.html#exclusion-markers) for
more information.

Even if your changes cannot be covered in the CI, we still encourage you to write the tests for them. This will allow
maintainers to run the tests locally.

[crowdin-url]: https://translate.lizardbyte.dev



| Previous                |                                                         Next |
|:------------------------|-------------------------------------------------------------:|
| [Building](building.md) | [Source Code](../third-party/doxyconfig/docs/source_code.md) |




  
  [TOC]

---

## File: docs/gamestream_migration.md

# GameStream Migration
Nvidia announced that their GameStream service for Nvidia Games clients will be discontinued in February 2023.
Luckily, Sunshine performance is now equal to or better than Nvidia GameStream.

## Migration
We have developed a simple migration tool to help you migrate your GameStream games and apps to Sunshine automatically.
Please check out our [GSMS](https://github.com/LizardByte/GSMS) project if you're interested in an automated
migration option. GSMS offers the ability to migrate your custom and auto-detected games and apps. The
working directory, command, and image are all set in Sunshine's `apps.json` file. The box-art image is also copied
to a specified directory.

## Internet Streaming
If you are using the Moonlight Internet Hosting Tool, you can remove it from your system when you migrate to Sunshine.
To stream over the Internet with Sunshine and a UPnP-capable router, enable the UPnP option in the Sunshine Web UI.

> [!NOTE]
> Running Sunshine together with versions of the Moonlight Internet Hosting Tool prior to v5.6 will cause UPnP
> port forwarding to become unreliable. Either uninstall the tool entirely or update it to v5.6 or later.

## Limitations
Sunshine does have some limitations, as compared to Nvidia GameStream.

* Automatic game/application list.
* Changing game settings automatically to optimize streaming.



| Previous                                        |              Next |
|:------------------------------------------------|------------------:|
| [Third-party Packages](third_party_packages.md) | [Legal](legal.md) |




  
  [TOC]

---

## File: docs/guides.md

# Guides

@admonition{Community | A collection of guides written by the community is available on our
[blog](https://app.lizardbyte.dev/blog).
Feel free to contribute your own tips and trips by making a PR to
[LizardByte.github.io](https://github.com/LizardByte/LizardByte.github.io).}



| Previous                                |                                        Next |
|:----------------------------------------|--------------------------------------------:|
| [Awesome-Sunshine](awesome_sunshine.md) | [Performance Tuning](performance_tuning.md) |




  
  [TOC]