Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/Navigation.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ search:
- [Authentication](troubleshooting/authentication.md)
- [In-Browser Play](troubleshooting/in-browser-play.md)
- [Netplay](troubleshooting/netplay.md)
- [Emulator Streaming](troubleshooting/emulator-streaming.md)
- [Synology](troubleshooting/synology.md)
- [Kubernetes](troubleshooting/kubernetes.md)
- About
Expand Down
91 changes: 91 additions & 0 deletions docs/troubleshooting/emulator-streaming.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
---
title: Emulator Streaming Troubleshooting
description: Fix emulator streaming setup, GPU and network issues
---

# Emulator Streaming Troubleshooting

## Test the container on its own first

Get the [webstation](../using/emulator-streaming.md#run-the-webstation-container) container working by itself before you add it to `config.yml`. Open its Selkies web UI from the machine you'll play on, launch a game from inside the emulator, and check that it runs at full speed. If it doesn't, nothing in RomM's config will fix it.

To confirm the GPU is in use, open a terminal inside the container and run `vkcube`. It should name your graphics card, and `llvmpipe` means the container fell back to software rendering. When a desktop container can't get the GPU at all, smoke-test a plain Selkies container such as [webtop](https://docs.linuxserver.io/images/docker-webtop/) with the [LinuxServer GPU guide](https://docs.linuxserver.io/selkies/user-guide/gpu/) before you go back to the emulator.

## The GPU isn't used, or the emulator fails to initialize

On NVIDIA, these are the only GPU settings a Selkies container needs:

```yaml
shm_size: 1gb
devices:
- /dev/nvidia-modeset:/dev/nvidia-modeset
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: 1
capabilities: [compute, video, graphics, utility]
```

On a standard Linux host, Compose only picks this up once NVIDIA is Docker's default runtime:

```bash
sudo nvidia-ctk runtime configure --runtime=docker
sudo systemctl restart docker
```

Start from a minimal compose file with only the image, the broker variables, ports, volumes and the block above. Extra settings such as `security_opt`, `QT_QPA_PLATFORM` or `PIXELFLUX_WAYLAND` can stop the emulator from starting, so add them back one at a time once it works.

## The container crashes without an error

Check the host's kernel log right after the crash. The first command shows NVIDIA driver (Xid) errors, and the second shows processes the kernel killed for running out of memory:

```bash
dmesg -T | grep -i xid
dmesg -T | grep -i "killed process"
```

If both are empty, look for session and connection errors in the container's own log:

```bash
docker logs <container> --since 10m | grep -i -E "timeout|idle|heartbeat|disconnect|session"
```

## No stream action on a platform

Either `streaming.enabled` is off, nothing is configured for that platform slug, or the config hasn't reloaded. The streaming config is read when the app loads, so refresh the page after editing `config.yml`.

A YAML mapping can't hold the same key twice, so a second `containers:` under `streaming:` replaces the first and only the containers in the last one show up. Put every entry under a single `containers:` list.

## The stream never loads, or fails outside your home network

The stream is an iframe the browser loads straight from `host`, so `host` has to be HTTPS and reachable from wherever the browser is. A LAN address works at home but gives a 502 or a blank player outside it. Open the `host` URL directly from the client machine to see what it does.

For remote play, put the container behind your [reverse proxy](../install/reverse-proxy.md) and set `host` to its public HTTPS address. Point the proxy at the container's plain HTTP port and let the proxy handle TLS.

The broker is served under the container's `SUBFOLDER` on the same origin as the stream, so a single proxy host covers both. `broker_host` is only called by the RomM server, so if you set it, it can stay on an internal address.

## Launch or save errors out

Either the server can't reach `broker_host` or the secret is wrong. Check that `STREAMING_BROKER_SECRET` matches the container's `BROKER_SECRET`, and that `broker_host` resolves from the RomM server. A `broker_secret` in `config.yml` is ignored whenever `STREAMING_BROKER_SECRET` is set (see [Set the shared secret](../using/emulator-streaming.md#set-the-shared-secret)).

## The emulator can't find the game

The path sent to the container is `library_path` (default `/romm/library`) followed by the ROM's path inside the RomM library, such as `roms/ps2/game.iso`. The container's mount has to mirror the RomM library layout under that prefix. If your library uses `roms/ps2/` and you mount the PS2 folder at `/romm/library/ps2/roms`, the emulator gets a path that doesn't exist. Either fix the mount or set `library_path` to wherever the container sees the library.

## Controllers or the virtual gamepad don't respond

Try another browser before anything else, because some don't pass gamepad input through to Selkies. Zen has failed on both Linux and macOS, while Firefox and Vivaldi work.

## A container shows as unconfigured

Its `host` is missing a scheme, or there's no reachable broker for it, and it can't be claimed until that's fixed.

## A platform is stuck as in use

Someone disconnected without releasing it. Wait for the heartbeat to go stale or force-release it from the fleet (see [Emulator Streaming](../using/emulator-streaming.md)).

## "The previous session is still saving"

An exit is still pulling state off the container, so give it a moment and try again. If saves on a slow container time out, raise `STREAMING_SAVE_TIMEOUT` (see [Environment Variables → Emulator Streaming](../reference/environment-variables.md#emulator-streaming)).
4 changes: 4 additions & 0 deletions docs/troubleshooting/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ description: Diagnose common issues by symptom
- EmulatorJS won't load/404 → [In-Browser Play Troubleshooting](in-browser-play.md) (on the slim image, cores come from a CDN at runtime, so a 404 usually means outbound networks are blocked).
- Netplay doesn't connect → [Netplay Troubleshooting](netplay.md) (the cause is almost always NAT or missing ICE servers)

## Emulator streaming

- Stream won't load, launch fails or the GPU isn't used → [Emulator Streaming Troubleshooting](emulator-streaming.md)

## Platform-specific

- [Synology Troubleshooting](synology.md): permission errors, DSM gotchas
Expand Down
11 changes: 3 additions & 8 deletions docs/using/emulator-streaming.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ streaming:
enabled: true
containers:
- protocol: webstation
host: https://192.168.1.56:3010
host: https://stream.example.com
subfolder: /streaming
label: Emulation station
platforms:
Expand All @@ -170,7 +170,7 @@ streaming:

Four of those keys have consequences worth knowing before you pick their values:

- `host` is what the browser connects to, and it has to be **HTTPS**: Selkies WebRTC won't run without a secure context. Use the container's self-signed cert, or put it behind a [reverse proxy with TLS](../install/reverse-proxy.md). A path like `/streaming` works if you've proxied the container onto RomM's own origin, but then you must set `broker_host` yourself, because a bare path gives RomM no address to call.
- `host` is what the browser connects to, and it has to be **HTTPS**: Selkies WebRTC won't run without a secure context. Put the container's plain HTTP port behind a [reverse proxy with TLS](../install/reverse-proxy.md). A path like `/streaming` works if you've proxied the container onto RomM's own origin, but then you must set `broker_host` yourself, because a bare path gives RomM no address to call.
- `broker_host` is only ever called server to server, so plain HTTP is fine. Pooled containers are identified by it, so two serving the same platform need different ones.
- `library_path` is where the container sees your library. Don't change it casually, since your state and save history is keyed to it.
- The per-platform `emulator` names what that platform's states and memory cards are filed under, so renaming it later orphans everything stored under the old name. A container-level `emulator` is ignored whenever `platforms` is used.
Expand All @@ -189,9 +189,4 @@ Three env vars bound how long streaming waits, listed with their defaults in [En

## Troubleshooting

- **No stream action on a platform.** Either `streaming.enabled` is off, nothing is configured for that platform slug, or the config hasn't reloaded. RomM reads the streaming config when the app loads, so refresh the page after editing `config.yml`.
- **Stream never loads.** The browser can't reach `host`, or `host` isn't HTTPS. Open the Selkies URL directly in a browser from the client machine and see what happens.
- **Launch or save errors out.** Either the server can't reach `broker_host` or the secret is wrong. Check `STREAMING_BROKER_SECRET` matches on both sides, and that `broker_host` actually resolves from the server.
- **A container shows as unconfigured in the fleet.** Its `host` is missing a scheme, or RomM has no reachable broker for it. It can't be claimed until that's fixed.
- **Platform stuck as in use.** Someone disconnected without releasing it. Wait for the heartbeat to go stale or force-release it from the fleet.
- **"The previous session is still saving".** An exit is still pulling state off the container. Give it a moment and try again.
Setup, GPU, reverse proxy and session issues are covered in [Emulator Streaming Troubleshooting](../troubleshooting/emulator-streaming.md).