{"id":20325105,"url":"https://github.com/mphe/cloud-gaming-in-a-box","last_synced_at":"2026-05-22T16:33:31.080Z","repository":{"id":207997429,"uuid":"716237503","full_name":"mphe/cloud-gaming-in-a-box","owner":"mphe","description":"A fully local Cloud-Gaming testbed that is easy to deploy, configure, extend and use.","archived":false,"fork":false,"pushed_at":"2023-11-18T22:16:22.000Z","size":220,"stargazers_count":0,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-04T10:29:38.674Z","etag":null,"topics":["cloud","emulation","gaming","latency","local","qoe","remote","streaming","studies","survey","testbed","user","video","wan"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mphe.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2023-11-08T18:06:31.000Z","updated_at":"2023-11-21T10:29:09.000Z","dependencies_parsed_at":"2023-11-19T01:26:40.587Z","dependency_job_id":"8f72a843-6b9c-4a67-9a35-6d436153ffbb","html_url":"https://github.com/mphe/cloud-gaming-in-a-box","commit_stats":null,"previous_names":["mphe/cloud-gaming-in-a-box"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/mphe/cloud-gaming-in-a-box","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mphe%2Fcloud-gaming-in-a-box","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mphe%2Fcloud-gaming-in-a-box/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mphe%2Fcloud-gaming-in-a-box/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mphe%2Fcloud-gaming-in-a-box/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mphe","download_url":"https://codeload.github.com/mphe/cloud-gaming-in-a-box/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mphe%2Fcloud-gaming-in-a-box/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33354036,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-21T12:23:38.849Z","status":"online","status_checked_at":"2026-05-22T02:00:06.671Z","response_time":265,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cloud","emulation","gaming","latency","local","qoe","remote","streaming","studies","survey","testbed","user","video","wan"],"created_at":"2024-11-14T19:38:44.589Z","updated_at":"2026-05-22T16:33:31.061Z","avatar_url":"https://github.com/mphe.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Cloud Gaming in a Box\n\nThis project provides a Cloud-Gaming testbed that is easy to deploy, configure, extend and use, with the goal of facilitating user studies for Cloud-Gaming or remote interactive applications in general.\n\n## Features\n* **Simple setup**\n  \n  Besides installing dependencies and compiling, the testbed requires no additional network or system configuration.\n  \n* **Fully local**\n\n  The testbed runs fully locally on a single computer without the need for VMs, multiple PCs or an internet connection.\n  *Cloud Gaming in a Box* essentially provides a remote-streaming-like service that runs on the same device.\n\n* **Run arbitrary applications**\n\n  The testbed can run arbitrary applications with a single simple command and without any additional configuration.\n\n* **Integrated WAN emulation**\n\n  A set of UDP/TCP proxies emulate typical WAN properties like delay, jitter and packet loss, in order to consistently recreate custom network scenarios as if the testbed was deployed in a traditional remote server-client environment.\nThis lifts the need for setting up intermediate network nodes with [WANem], [tc] or [Dummynet] for WAN emulation.\n\n\n## Table of Contents\n\n\u003c!-- vim-markdown-toc GFM --\u003e\n\n- [Features](#features)\n- [Related Work](#related-work)\n- [Setup](#setup)\n- [Compatibility](#compatibility)\n- [Usage](#usage)\n  - [Basic usage](#basic-usage)\n  - [Passing configuration options](#passing-configuration-options)\n  - [Using provided wrapper scripts](#using-provided-wrapper-scripts)\n  - [Running only selected subsystems](#running-only-selected-subsystems)\n- [Configuration](#configuration)\n- [Conducting User Surveys](#conducting-user-surveys)\n  - [Procedure](#procedure)\n  - [Usage](#usage-1)\n- [Architecture](#architecture)\n- [Running Steam Proton Games](#running-steam-proton-games)\n- [Fixing Video Corruption](#fixing-video-corruption)\n- [Limitations and Future Work](#limitations-and-future-work)\n- [Contributing](#contributing)\n\n\u003c!-- vim-markdown-toc --\u003e\n\n\n## Related Work\n\nThere are various tools for low latency remote streaming like [Parsec] or [Moonlight].\nThe only open source Cloud-Gaming testbed that was specifically developed for academic use is [GamingAnywhere].\nHowever, all these systems are meant to be deployed in a traditional distributed environment and do not provide means for WAN emulation on their own.\nAdditionally, they might require the use of proprietary services or specific hardware.\nThis results in a significant amount of work for setting up reliable testbed environments.\n\nIn comparison to [GamingAnywhere], this testbed is much simpler in terms of functionality and Lines-of-Code, does not contain any unnecessary features, like a portal server for game selection, includes efficient support for VSync, incorporates WAN emulation, is easily deployable, runs fully locally and requires no further setup besides installing software dependencies and compiling.\n\nOn the downside, at this moment, the testbed only supports Linux with X11 (see also [Compatibility](#compatibility)).\nAdditionally, GamingAnywhere supports capturing application video by injecting code into the target process and reading the framebuffer directly when it was updated.\nEven though this method only works for certain frameworks, it can improve the performance and circumvent visual artifacts.\nSee also [Limitations and Future Work](#limitations-and-future-work).\n\n\n## Setup\n\n1. Clone the repository\n2. Run `git submodule update --init --recursive`\n3. Install requirements\n    - **NOTE**: Requires FFmpeg 5+.\n    - Arch\n        ```sh\n        sudo pacman -S go base-devel cmake xorg-server-xvfb virtualgl ffmpeg sdl2 xdotool\n        ```\n    - Ubuntu\n        ```sh\n        sudo apt install golang build-essential make cmake libsdl2-dev libsdl2-2.0-0 ffmpeg libavcodec-dev libavutil-dev libavformat-dev libxtst-dev xvfb\n        ```\n        In addition, download and install VirtualGL. See \u003chttps://virtualgl.org/vgldoc/2_1_3/#hd004001\u003e.\n4. Run `./build.sh` to compile all components\n\n\n## Compatibility\n\nThe testbed only works on Linux, but all tools were written with cross-platform compatibility in\nmind, so they can be ported to other platforms in a reasonable amount of time.\n\nThe exception is the backend, which is based on Xvfb, which in turn is only available on systems using X11.\nThe run script also needs to be adapted accordingly and might need a rewrite on platforms that do\nnot support Bash.\n\n\n## Usage\n\nThe run-script `run.sh` performs necessary setup, creates a virtual audio sink, starts all individual components and cleans up afterwards.\nTo ease debugging in case of failure, it redirects the output of all components to individual log files located in the `logs/` directory.\n\n### Basic usage\n\nRun the testbed using: `./run.sh \u003capplication\u003e [subsystems]`.\n\nSee also `./run.sh -h` for advanced usage.\n\n```sh\n# Warsow\n./run.sh warsow\n\n# Libre Office Calc with additional arguments\n./run.sh localc \"\" --norestore --show\n```\n\n### Passing configuration options\n\nThe testbed can be configured using environment variables.\nSee [below](#configuration) for a list of available configuration options.\n\n```sh\n# Warsow with 640x480 px resolution\nWIDTH=640 HEIGHT=480 ./run.sh warsow\n\n# Warsow with VSync enabled\nFRONTEND_VSYNC=true ./run.sh warsow\n\n# Warsow with 50 ms RTT\nSERVER_DELAY_MS=25 CLIENT_DELAY_MS=25 ./run.sh warsow\n```\n\n### Using provided wrapper scripts\n\n`scenarios/` contains wrapper scripts for various example network scenarios.\n`apps/` contains example scripts for starting certain applications.\n`cfg/` contains some wrapper scripts for common configurations, like VSync.\n\n```sh\n# Warsow with VSync enabled\ncfg/vsync.sh ./run.sh warsow\n\n# Warsow with VSync enabled and a delay scenario\nscenarios/delay1.sh cfg/vsync.sh ./run.sh warsow\n\n# Libre Office Calc\n./run.sh apps/localc.sh\n\n# A Hat in Time with VSync enabled\ncfg/vsync.sh cfg/proton.sh ./run.sh apps/hatintime.sh\n```\n\n### Running only selected subsystems\n\n`run.sh` also supports running only specific subsystems. This can be used to specifically start and\nkill only selected components of the testbed.\n\nFor example, when testing multiple network scenarios, the application and streaming components can\nbe run in one session, and the remaining subsystems in another session.\nThis allows to quickly kill and restart the \"frontend\" with another configuration without having to\nrestart the whole game.\n\nWhen starting only certain subsystems, obsolete parameters have no effect and can be left empty.\n\n```sh\n# Run A Hat in Time, but only the application and streaming components (\"backend\")\ncfg/proton.sh ./run.sh apps/hatintime.sh app,stream\n\n# (In another terminal) Run remaining components with delay scenario 1.\nscenarios/delay1.sh cfg/vsync.sh ./run.sh \"\" proxy,syncinput,frontend\n\n# Press ctrl-c anytime\n\n# Attach again with delay scenario 3, without killing the game process.\nscenarios/delay3.sh cfg/vsync.sh ./run.sh \"\" proxy,syncinput,frontend\n```\n\n\n## Configuration\n\nThe `run.sh` script defines various environment variables for configuration purposes.\nThe following table shows all available settings and their defaults.\nThe `cfg/` directory contains some wrapper scripts for common configurations, like VSync, and `scenarios/` contains wrapper scripts for various example network scenarios.\n\nSee also [Usage](#usage) for examples on how to apply these settings.\n\n| Environment variable   | Default | Description                                                                                 |\n|------------------------|---------|---------------------------------------------------------------------------------------------|\n| `WIDTH`                | 1920    | Horizontal resolution of the video stream                                                   |\n| `HEIGHT`               | 1080    | Vertical resolution of the video stream                                                     |\n| `FPS`                  | 60      | Video stream FPS                                                                            |\n| `VIDEO_BITRATE`        | 25M     | Video stream bitrate                                                                        |\n| `FRONTEND_VSYNC`       | false   | Enable VSync in the frontend                                                                |\n| `XVFB_KEYBOARD_LAYOUT` |       | Keyboard layout to use in Xvfb. If not specified, automatically detects the current layout. |\n| `SYNCINPUT_PROTOCOL`   | tcp     | Network protocol to use with syncinput. Can be *tcp* or *udp*.                              |\n| `MOUSE_SENSITIVITY`    | 1       | Mouse sensitivity applied in the frontend. Experimental, does not work as expected.         |\n| `USE_VIRTUALGL`        | true    | Whether to use VirtualGL. Needs to be disabled when running Vulkan applications.            |\n\nWAN emulation settings for Audio/Video streams, i.e. from backend to frontend.\n\n| Environment variable | Default | Description                               |\n|----------------------|---------|-------------------------------------------|\n| `SERVER_DELAY_MS`    | 0       | Delay in milliseconds                     |\n| `SERVER_JITTER_MS`   | 0       | Maximum jitter in milliseconds            |\n| `SERVER_LOSS_START`  | 0       | Probability of burst packet loss to begin |\n| `SERVER_LOSS_STOP`   | 1.0     | Probability of burst packet loss to end   |\n\nWAN emulation settings for the input stream, i.e. from frontend to backend.\n\n| Environment variable | Default | Description                               |\n|----------------------|---------|-------------------------------------------|\n| `CLIENT_DELAY_MS`    | 0       | Delay in milliseconds                     |\n| `CLIENT_JITTER_MS`   | 0       | Maximum jitter in milliseconds            |\n| `CLIENT_LOSS_START`  | 0       | Probability of burst packet loss to begin |\n| `CLIENT_LOSS_STOP`   | 1.0     | Probability of burst packet loss to end   |\n\n\n## Conducting User Surveys\n\nThe `survey/run_scenarios.py` script provides a fully automatic workflow for conducting user studies using this testbed.\nIt might need to be adapted depending on use-case.\n\nAt the top of the script various settings are defined regarding the survey process.\nThis includes a list of available scenarios in addition to a baseline scenario that does not consist of any disturbances, providing the best possible experience with this setup.\n\nGraphical dialogs and prompts are implemented using tkinter and are therefore straightforward to extend and adapt.\n\nAll data gathered will be written to CSV immediately to prevent data loss and to allow easy resuming in case of failure.\n\n\n### Procedure\n\nThe procedure looks as follows:\n1. Survey\n2. Warm-up\n3. Test scenarios - Round 1\n4. Baseline\n5. Test scenarios - Round 2\n\nThe script starts with a short survey about age, gender, average time spent on gaming per week, preferred game genres and preferred gaming hardware.\n\nAfterwards, the user gets 5 minutes warm-up time with the baseline scenario to get familiar with the game.\nIn the last 5 seconds an alarm sound will play to notify the user that the time is almost up.\n\nAfter warm-up, each of the defined test scenarios will be executed in randomized order.\nEach scenario will last for one minute and ends with an alarm sound as usual.\nAfterwards, the user receives a prompt to rate their QoE between 1-5 points, according to a standard MOS scale.\n\nAfter all scenarios were finished, the baseline scenario will appear again for one minute, followed by a rating dialogue and a second round of scenarios.\n\nThe whole procedure takes around 30 minutes.\n\n\n### Usage\n\nUsage: `run_scenarios.py [-h] [-u USER] [-o OFFSET]`.\nSee also `run_scenarios.sh -h`.\n\nThe script can be run locally on the target machine or over SSH.\n\nAt the top of the script are various constants that can be adapted.\n\nAt the start, the script uses the current timestamp as random seed and user ID.\nThis ID will also be the filename of the generated CSV.\n\nThe `-u` option allows specifying a custom ID/seed.\n\nThe `-o` option allows specifying at which scenario the script should start.\nThis is useful in case of failure to continue were the process was stopped.\nIn that case, the `-u` option should be set to the failed session's ID.\n\n\n## Architecture\n\n\u003cimg src=\"img/architecture.png\" width=400px align=\"right\"/\u003e\n\nThe testbed is a modular stack of different software components.\nIt was initially based on [Cloud-Morph], hence the overall architecture is similar.\nHowever, due to Cloud-Morph turning out to be insufficient regarding the requirements of this project, all of its components have been replaced with custom implementations, in particular the frontend has been changed from a webpage to a native application.\n\nThe backend employs Xvfb for rendering and controlling the target application in a headless environment.\nTwo FFmpeg instances are used for capturing and providing Audio/Video streams of the target application over RTP.\nThe video stream uses H.264 and the audio stream uses Opus.\nThe input synchronization tool (`syncinput`) receives input events from the frontend over TCP and replicates them to target application running in the headless environment.\n\nAs Xvfb does not support hardware accelerated OpenGL rendering, VirtualGL is used to run the application with hardware acceleration enabled.\nVulkan applications do not suffer from this problem and always benefit from hardware acceleration.\n\nThe frontend is a single application optimized for efficiently decoding and playing back the audio and video stream, while transmitting user inputs with minimal delay to the `syncinput` tool.\n\nThe RTP and TCP traffic is routed through a WAN emulation layer, which consists of multiple proxies relaying the incoming traffic while performing WAN emulation.\nFor TCP, [Toxiproxy] is used, while for UDP a [custom proxy](https://github.com/mphe/udp-wan-proxy/tree/master) has been developed.\n\nTechnically, since the testbed uses regular networking protocols, it could also be deployed in a traditional distributed server-client environment.\nEven though it is possible, it is not advised to deploy this system remotely over internet, because of lacking security measures like traffic encryption.\nAdditionally, such a setup is not supported by the run-script and would require manual adaption.\n\n\n## Running Steam Proton Games\n\n1. Edit the game's launch configuration in steam: `PROTON_DUMP_DEBUG_COMMANDS=1 PROTON_DEBUG_DIR=$HOME %command%`\n2. Run the game\n3. Steam dumps corresponding run scripts to `~/proton_\u003cuser\u003e/` (`gdb_attach`, `gdb_run`, `run`, `winedbg`, `winedbg_run`)\n4. Use the generated `run` script as execution target for `run.sh`\n    - Optionally, remove the line with `WINEDEBUG=\"-all\"` from `run` script.\n5. Set `USE_VIRTUALGL=false` when executing `run.sh` to disable VirtualGL.\n    - Proton makes use of Vulkan, hence VirtualGL is not needed and will also not work.\n    - `cfg/proton.sh` is a wrapper script that sets `USE_VIRTUALGL=false` and can be used for simplicity.\n\n\n## Fixing Video Corruption\n\nSee [here](https://github.com/mphe/udp-wan-proxy/tree/master#video-corruption).\n\n\n## Limitations and Future Work\n\nMost limitations are missing features that can be added with more development time.\n\n- Cross-platform support\n  - Only Linux is supported\n- Add controller support\n  - Only mouse and keyboard are supported\n- Automatic reconnecting after connection loss\n  - Restarting single components, e.g. proxies, causes other components that are connected to lose their connection and exit\n  - Hence, restarting one component often requires also restarting other components\n  - Automatic reconnection should be added to solve this issue\n- Change configuration during runtime\n  - Currently, components must be restarted to change the configuration\n  - Especially the UDP WAN proxies would profit from being able to seamlessly change configurations during runtime, similar to [Toxiproxy]\n- Improve application and screen capturing performance\n  - Xvfb only supports software rendering, hence VirtualGL is used\n  - Still a noticeable performance degradation\n  - Possible solutions\n    - Inject code into target process and grab framebuffer directly, like [GamingAnywhere] does\n      - Heavily dependent on the underlying framework and OS\n      - Could trigger anti-cheat protection of some games\n    - Create a custom VirtualGL transport plugin to grab the finished framebuffer and send it directly to FFmpeg\n      - Only works for OpenGL applications, not Vulkan.\n- Screen tearing in FFmpeg recording\n  - FFmpeg continuously captures the screen in the virtual environment\n  - When the screen updates, it might cause screen tearing that is visible in the recording\n  - There is no VSync in a headless environment\n  - Might not occur in Wayland?\n  - Could be solved with one of the above alternative capturing solutions\n- Inconsistent mouse sensitivity\n  - Mouse movement is transmitted from the frontend to the backend\n  - For some reason, there is faster mouse movement in the backend\n- Packet loss recovery\n  - The testbed does not provide any means for packet loss recovery\n  - Even small amounts of packet loss result in heavy image corruption\n  - Commercial Cloud-Gaming services provide means for packet loss recovery\n  - Possible solutions\n    - Implement in application\n        - [RTP standard](https://www.rfc-editor.org/rfc/rfc4588.html) defines a framework for packet retransmission but needs manual implementation\n        - Create a custom streaming service\n        - Frontend tracks lost packets and asks for retransmission\n        - Streaming service retransmits lost packets on a separate channel\n    - Use SRT instead of RTP\n      - Provides similar performance as RTP and incorporates packet retransmissions out-of-the-box\n      - Supported by FFmpeg\n      - Could theoretically be switched seamlessly without any additional work\n- Network security\n  - The testbed was intended for local use\n  - Traffic is not encrypted\n  - Should use TLS based protocols\n- Inputs can get stuck on exit\n  - If the frontend quits while a key is pressed, the corresponding key-release event is never sent\n  - This causes the application in the backend to still receive inputs even though there are none\n  - Happened regularly during the user study\n  - Frontend should track inputs and send release-events before exiting\n\n\n## Contributing\n\nContributions are welcome!\n\n\n[WANem]: https://wanem.sourceforge.net/\n[tc]: https://man7.org/linux/man-pages/man8/tc.8.html\n[Dummynet]: http://info.iet.unipi.it/~luigi/dummynet/\n[Parsec]: https://parsec.app/\n[Moonlight]: https://moonlight-stream.org/\n[GamingAnywhere]: https://gaminganywhere.org/\n[Cloud-Morph]: https://github.com/giongto35/cloud-morph\n[Toxiproxy]: https://github.com/Shopify/toxiproxy\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmphe%2Fcloud-gaming-in-a-box","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmphe%2Fcloud-gaming-in-a-box","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmphe%2Fcloud-gaming-in-a-box/lists"}