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
33 changes: 18 additions & 15 deletions docs/reference/configuration-file.md
Original file line number Diff line number Diff line change
Expand Up @@ -564,20 +564,22 @@ streaming:

Add 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`. When 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`. When 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:<core>` to pick a RetroArch core, or a block overriding `emulator`, `label`, `memory_card_sync`, `core` and `experimental_cores` for that platform.

```yaml
streaming:
Expand All @@ -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
Expand All @@ -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.

Expand Down
30 changes: 27 additions & 3 deletions docs/using/emulator-streaming.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ There's one display per container, so a container runs one session at a time no

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

Expand All @@ -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 and you need to 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. 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

Three separate things move between the container and your library. Which ones apply depends on the platform.
Expand All @@ -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.

Expand Down Expand Up @@ -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
Expand Down