# cloud/media_server_next — Mediasoup Media Server

The forwarder for real-time audio, video, and movement/data streams in Bigscreen multiplayer rooms. Built on [mediasoup](https://mediasoup.org/). Each process can host many rooms; each room has its own mediasoup router; each user in a room has its own set of transports (data, mic, audio, video) and producers/consumers.

This doc covers `media_server_next` — the portable, "runs anywhere" version. The older AWS-specific variant, `media_server_aws`, is noted at the end.

**Entry:** [cloud/media_server_next/media_server_next.ts](../../cloud/media_server_next/media_server_next.ts).
**Package:** `bigscreen_media_server_next`.
**Depends on:** [`@bigscreen/lib`](../libraries/lib.md), [`@bigscreen/cloud`](../libraries/cloud-handlers.md), [`mediasoup`](https://mediasoup.org/), `sctp`.

## Peer Topology

Each connected user is a `Peer` with separate plain-transport sockets for each kind of stream. The server keeps three sets of mediasoup routers, one per logical grouping (room, group, screen share).

```mermaid
flowchart TB
    subgraph Process["media_server_next process"]
        subgraph Routers
            RR["roomRouters<br/>{ roomId → Router }"]
            GR["groupRouters<br/>{ groupId → Router }"]
            SR["screenRouters<br/>{ screenId → Router }"]
        end

        subgraph Peer["Peer (per user)"]
            DT["dataTransport +<br/>dataProducer +<br/>dataConsumers list"]
            MT["micTransport +<br/>micProducer +<br/>micConsumers list"]
            AT["audioTransport +<br/>audioProducer +<br/>audioConsumers list"]
            VT["videoTransport +<br/>videoProducer +<br/>videoConsumers list"]
        end

        subgraph Screen["ScreenPeer (per shared screen)"]
            SDT[dataTransport]
            SAT[audioTransport]
            SVT[videoTransport]
        end
    end

    USER["VR / Web client"] <-.RTC.-> DT
    USER <-.RTC.-> MT
    USER <-.RTC.-> AT
    USER <-.RTC.-> VT

    SHARER["Screen sharer"] <-.RTC.-> SDT
    SHARER <-.RTC.-> SAT
    SHARER <-.RTC.-> SVT
```

Each `dataTransport`, `micTransport`, `audioTransport`, `videoTransport` is a mediasoup `PlainTransport`. Consumers forward a producer's stream to other peers in the same room/group. The split between mic and audio exists so voice and game / media audio can be mixed independently.

## Startup Handshake

Media servers must register with `cloud_api` before they do anything. Registration yields an auth token they subsequently use on HTTP calls back to `cloud_api`.

```mermaid
sequenceDiagram
    autonumber
    participant P as Node process
    participant ENV as dotenv
    participant MS as MediaServerConfig
    participant CAPI as cloud/cloud_api
    participant MSW as mediasoup.Worker

    P->>ENV: dotenv.config()
    P->>MS: populate id, announcedIp, region,<br/>minPort=10000, maxPort=59999
    P->>MSW: mediasoup.createWorker()
    P->>CAPI: POST /api/media-server/register
    CAPI-->>P: { authToken }
    P->>P: start polling RemoteQueue<br/>for commands
    P->>P: start heartbeat interval
    Note over P: Ready to create rooms
```

Why HTTP for registration (not SQS)? Because media servers often run outside AWS (Digital Ocean, bare metal) and SQS isn't directly reachable. `RemoteQueue` is an HTTP-based wrapper around the same queue semantics: media servers POST messages to `cloud_api`, which enqueues them in `BigscreenCloud`; outbound commands come back via a poll of a dedicated queue endpoint.

## Communication with `cloud_api`

| Direction | Mechanism | Purpose |
|-----------|-----------|---------|
| ms → cloud (inbound command) | HTTP POST `/api/media-server/message` | Heartbeat, Registered, RoomCreated, UserConnected, etc. |
| cloud → ms (outbound command) | HTTP long-poll via `RemoteQueue` | RoomCreationRequest, UserConnectionRequest, etc. |
| Peer ↔ ms | RTC (UDP 10000–59999) | Actual media payload |

See [cloud/src/RemoteMessageQueue.ts](../../cloud/src/RemoteMessageQueue.ts) for the `RemoteQueue` transport.

## Expiration & Cleanup

A peer accumulates an `expiredCount` on each tick the server hasn't seen any activity from them. When it crosses the threshold, the peer is cleaned up: transports closed, consumers removed from other peers, and a `UserDisconnected` message sent to the cloud. This catches abrupt disconnects that the mediasoup layer doesn't notice immediately.

## Port Range

Mediasoup workers occupy **UDP 10000–59999** by default (configurable in `MediaServerConfig`). If you're running locally, those need to be free and reachable (or at least port-forwarded behind your NAT). If you're running on AWS, the security group must allow that range on UDP.

## Legacy: `cloud/media_server_aws`

[`cloud/media_server_aws/media_server_aws.ts`](../../cloud/media_server_aws/media_server_aws.ts) is the original AWS-specific implementation. It:

- Used SQS directly instead of `RemoteQueue` (assumed AWS)
- Had AWS-specific instance-metadata lookups
- Managed a different peer/router model

It is kept for historical comparison and still runs on some fleets. New work should go into `media_server_next`. See the README inside that folder for details.

## Further reading

- Cloud-side of the room lifecycle → [services/cloud-api.md](./cloud-api.md)
- How mediasoup commands get routed → [services/cloud-worker.md](./cloud-worker.md)
- A worked example of room creation → [data-flows.md#2-room-creation](../data-flows.md#2-room-creation)
- In-flight latency notes → [../debug_media_server_delay.md](../debug_media_server_delay.md)
