From 1fbad134e57276fb4a5ef31b6bf18c879a96ad3e Mon Sep 17 00:00:00 2001 From: Zach Clendenen Date: Sun, 27 Sep 2026 18:09:35 -0500 Subject: [PATCH 1/2] docs(streaming): document the RetroArch core override --- docs/reference/configuration-file.md | 33 +++++++++++++++------------- docs/using/emulator-streaming.md | 30 ++++++++++++++++++++++--- 2 files changed, 45 insertions(+), 18 deletions(-) diff --git a/docs/reference/configuration-file.md b/docs/reference/configuration-file.md index 54970326..a67cca37 100644 --- a/docs/reference/configuration-file.md +++ b/docs/reference/configuration-file.md @@ -564,20 +564,22 @@ streaming: **One entry per container**, not per platform. A container serves every platform listed in its `platforms` map, and its own keys are the defaults for all of them. -| Key | Required | Purpose | -| ------------------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| `host` | Yes | Browser-facing Selkies web UI, served over **HTTPS**, or a path when reverse proxied onto RomM's own origin | -| `platforms` | Yes | Map of [platform slug](../platforms/supported-platforms.md) to the emulator serving it, or to an override block | -| `protocol` | No | `webstation`. Omitted, the entry is read as a deprecated per-emulator broker mod | -| `label` | No | Name for the container, shown in the fleet view. The play action is named after the emulator instead | -| `subfolder` | No | URL prefix the broker is served under, matching the container's `SUBFOLDER` | -| `broker_host` | No | Server-to-broker API base. Derived from `host` when omitted, and **required** when `host` is a path | -| `broker_secret` | No | Secret for this container, used only when the `STREAMING_BROKER_SECRET` env var is unset | -| `library_path` | No | In-container path to the RomM library, if it is mounted somewhere other than the default `/romm/library` | -| `emulator` | No | Lowercased name grouping states and memory cards. Ignored when `platforms` is used, since each platform's own emulator names them | -| `memory_card_sync` | No | Sync the whole memory card to the RomM library. Ignored only on platforms known to have no card (`wii`, `psx`, `ps3`, `ps4`, `xbox`, `xbox360`, `wiiu`, `3ds`, `switch`) | - -Each `platforms` value is either the emulator name on its own, or a block overriding `emulator`, `label` and `memory_card_sync` for that platform. +| Key | Required | Purpose | +| -------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `host` | Yes | Browser-facing Selkies web UI, served over **HTTPS**, or a path when reverse proxied onto RomM's own origin | +| `platforms` | Yes | Map of [platform slug](../platforms/supported-platforms.md) to the emulator serving it, or to an override block | +| `protocol` | No | `webstation`. Omitted, the entry is read as a deprecated per-emulator broker mod | +| `label` | No | Name for the container, shown in the fleet view. The play action is named after the emulator instead | +| `subfolder` | No | URL prefix the broker is served under, matching the container's `SUBFOLDER` | +| `broker_host` | No | Server-to-broker API base. Derived from `host` when omitted, and **required** when `host` is a path | +| `broker_secret` | No | Secret for this container, used only when the `STREAMING_BROKER_SECRET` env var is unset | +| `library_path` | No | In-container path to the RomM library, if it is mounted somewhere other than the default `/romm/library` | +| `emulator` | No | Lowercased name grouping states and memory cards. Ignored when `platforms` is used, since each platform's own emulator names them | +| `memory_card_sync` | No | Sync the whole memory card to the RomM library. Ignored only on platforms known to have no card (`wii`, `psx`, `ps3`, `ps4`, `xbox`, `xbox360`, `wiiu`, `3ds`, `switch`) | +| `core` | No | RetroArch only, set on a platform: the libretro core to boot instead of the broker's default. See [Picking a RetroArch core](../using/emulator-streaming.md#picking-a-retroarch-core) | +| `experimental_cores` | No | `true` lets a `core` the broker lists as known broken launch anyway. Set on the container or a platform block, where the platform wins | + +Each `platforms` value is either the emulator name on its own, `retroarch:` to pick a RetroArch core, or a block overriding `emulator`, `label`, `memory_card_sync`, `core` and `experimental_cores` for that platform. ```yaml streaming: @@ -591,6 +593,7 @@ streaming: label: Emulation station platforms: snes: retroarch # the emulator name directly... + gba: retroarch:gpsp # ...with a RetroArch core... ps2: # ...or a block overriding container keys emulator: pcsx2 label: PCSX2 @@ -601,7 +604,7 @@ streaming: memory_card_sync: true ``` -Platforms listed on several containers form a pool, with each claim taking the first free lane. Pool members have to agree on `emulator`, `memory_card_sync` and `protocol`, and are differentiated by broker host, so give each one a distinct `broker_host` (see [Emulator Streaming → How a session works](../using/emulator-streaming.md#how-a-session-works)). +Platforms listed on several containers form a pool, with each claim taking the first free lane. Pool members have to agree on `emulator`, `memory_card_sync`, `protocol`, `core` and `experimental_cores`, and are differentiated by broker host, so give each one a distinct `broker_host` (see [Emulator Streaming → How a session works](../using/emulator-streaming.md#how-a-session-works)). See [Emulator Streaming → Memory cards](../using/emulator-streaming.md#memory-cards) for how `memory_card_sync` behaves, and [Migrating to webstation](../using/emulator-streaming-migration.md) if you still run the per-emulator broker mods. diff --git a/docs/using/emulator-streaming.md b/docs/using/emulator-streaming.md index d5f17922..41f222f0 100644 --- a/docs/using/emulator-streaming.md +++ b/docs/using/emulator-streaming.md @@ -21,7 +21,7 @@ There's one display per container, so a container runs **one session at a time** List the same platform on several containers and you get a **pool**. RomM walks them in config order and grabs the first free one, so two people can play SNES at once if you've got two containers. If they're all busy, RomM checks for sessions whose heartbeat has gone quiet (someone closed a tab, a browser crashed) and clears those out before telling you the platform is in use. -Containers only pool together if they agree on `emulator`, `memory_card_sync` and `protocol`. Those three decide where saves end up and which controls the player offers, and it would be a bad surprise to land on a pool member and find your saves missing. Containers that differ are treated as separate setups. +Containers only pool together if they agree on `emulator`, `memory_card_sync` and `protocol`, and for RetroArch on `core` and `experimental_cores` too. Those decide where saves end up and which controls the player offers, and it would be a bad surprise to land on a pool member and find your saves missing. Containers that differ are treated as separate setups. ## Supported platforms @@ -45,10 +45,33 @@ The broker ships standalone emulators for the platforms below, and RetroArch for | _(anything else)_ | RetroArch | One resume state | - | Varies | | _(adventure games)_ | ScummVM | One resume state | - | - | -RetroArch covers dozens of platforms from the one container. The broker picks the core, not RomM, and RomM just labels the action with whatever core that is (`RA Snes9x`, `RA mGBA`). If you want to change the mapping it's the broker's `retroarch_platforms.json`. +RetroArch covers dozens of platforms from the one container. Out of the box the broker boots its best-tested core for each platform, and RomM labels the action with that core (`RA Snes9x`, `RA mGBA`). ROMs are launched as plain files, so **archives won't work**. Extract them first. +### Picking a RetroArch core + +To run a platform on a different libretro core, name it in `config.yml`, either after the emulator or as `core` in a platform block: + +```yaml +platforms: + gba: retroarch:gpsp # shorthand: emulator:core + n64: # or a block + emulator: retroarch + core: parallel_n64 +``` + +What happens at launch depends on how well the broker knows that core on that platform (the tiers are listed in the broker's [RetroArch core guide](https://romm-streaming.github.io/romm-broker/docs/emulators/retroarch-cores#choosing-a-core)): + +- **Vetted cores** launch like the default. +- **Untested cores** launch, and the player sees a warning that nobody has tested this core on this platform yet. +- **Known broken cores** are refused unless you set `experimental_cores: true` on the platform block or the container (or `RETROARCH_EXPERIMENTAL_CORES=true` on the broker). Opted in, they launch with a warning too. +- **A core the broker doesn't offer on that platform** fails the launch with the broker's message. + +`core` only works on `protocol: webstation` containers, and needs a broker recent enough to take it. An older broker ignores the core and boots its default, so RomM ends that session without keeping any saves from it and tells the player to upgrade the container or remove `core`. + +Save states are core-specific, so RomM records which core wrote each one. The resume picker only lists states the running core can load, and only those get restored onto the container. Switch back to the old core and its states show up again. In-game saves are a different story: the broker carries them over when you switch cores (see [Saves and states when switching cores](https://romm-streaming.github.io/romm-broker/docs/emulators/retroarch-cores#saves-and-states-when-switching-cores)). + ## Saves and save states Three separate things move between the container and your library. Which ones apply depends on the platform. @@ -61,7 +84,7 @@ These are the emulator's own snapshots, and the table above says which of three - **A single resume state.** These emulators only write a state as they shut down, so there's no grid to pick from, just the one state that saving and resuming both use. - **No states at all.** You rely on the game's own save data instead. -Whenever a state is written, RomM copies it off the container, along with a thumbnail grabbed from the video. The state from save-and-exit is collected when the session closes. Claim a container later and RomM pushes your stored states back onto it, which is why they follow you between containers and survive a container being rebuilt. +Whenever a state is written, RomM copies it off the container, along with a thumbnail grabbed from the video. The state from save-and-exit is collected when the session closes. Claim a container later and RomM pushes your stored states back onto it, which is why they follow you between containers and survive a container being rebuilt. On RetroArch only the states the running core can load go back ([Picking a RetroArch core](#picking-a-retroarch-core)). RomM keeps the most recent `STREAMING_STATE_HISTORY_LIMIT` states per game, per emulator, per user (default `50`, or `0` to keep everything) and prunes the rest. @@ -139,6 +162,7 @@ streaming: label: Emulation station platforms: snes: retroarch # just the emulator name... + gba: retroarch:gpsp # ...with a RetroArch core... ps2: # ...or a block overriding container keys emulator: pcsx2 memory_card_sync: true From eab80539482bab6192bc46ca0366c164a41bff76 Mon Sep 17 00:00:00 2001 From: Zach Clendenen Date: Sun, 27 Sep 2026 18:11:03 -0500 Subject: [PATCH 2/2] docs(streaming): humanize the RetroArch core override prose --- docs/using/emulator-streaming.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/using/emulator-streaming.md b/docs/using/emulator-streaming.md index 41f222f0..ea322a64 100644 --- a/docs/using/emulator-streaming.md +++ b/docs/using/emulator-streaming.md @@ -70,7 +70,7 @@ What happens at launch depends on how well the broker knows that core on that pl `core` only works on `protocol: webstation` containers, and needs a broker recent enough to take it. An older broker ignores the core and boots its default, so RomM ends that session without keeping any saves from it and tells the player to upgrade the container or remove `core`. -Save states are core-specific, so RomM records which core wrote each one. The resume picker only lists states the running core can load, and only those get restored onto the container. Switch back to the old core and its states show up again. In-game saves are a different story: the broker carries them over when you switch cores (see [Saves and states when switching cores](https://romm-streaming.github.io/romm-broker/docs/emulators/retroarch-cores#saves-and-states-when-switching-cores)). +Save states are core-specific, so RomM records which core wrote each one. The resume picker only lists states the running core can load, and only those get restored onto the container. Switch back to the old core and its states show up again. The broker does carry in-game saves over when you switch cores (see [Saves and states when switching cores](https://romm-streaming.github.io/romm-broker/docs/emulators/retroarch-cores#saves-and-states-when-switching-cores)). ## Saves and save states