# `ExLibSRT.Server`
[🔗](https://github.com/membraneframework/ex_libsrt/blob/v0.2.1/lib/ex_libsrt/server.ex#L1)

Implementation of the SRT server.

## Glossary

* **Stream ID** — An optional string identifier carried by each SRT connection. Clients can specify
  a stream ID when connecting, and the server can use it to identify and route connections.
* **Owner** — The process that receives notifications about new connections (`t:srt_server_conn/0`),
  rejected connections (`{:srt_server_rejected_client, stream_id}`), and server errors
  (`t:srt_server_error/0`).
* **Receiver** — The process that receives data messages (`t:srt_data/0`) and disconnection
  notifications (`t:srt_server_conn_closed/0`) for a specific connection. Can be bound via
  `bind_with_process/3` or `bind_with_handler/3`.

## Accepting connections
### whitelist mode
Each SRT connection can carry a `streamid` string which can be used for identifying the stream.
When `accept_mode: :whitelist` or `accept_mode: {:whitelist, ids}` the server operates in
**whitelist mode**: only connections whose `streamid` is present in the whitelist are accepted.

The whitelist can be supplied up-front via the `:accept_mode` option of `start/3` / `start_link/3`
(e.g., `accept_mode: {:whitelist, stream_ids}`), and modified at runtime with
`add_stream_id_to_whitelist/2` and `remove_stream_id_from_whitelist/2`.

When a client connects with a stream ID that is not on the whitelist, the server responds with
rejection code `1403` (analogous to HTTP 403 Forbidden).

### accept-all mode
When `accept_mode: :accept_all` the server operates in **accept-all mode**:
every incoming connection is accepted at the SRT level regardless of its stream ID.

In both modes the owner process receives a `t:srt_server_conn/0` message for each accepted
connection. The owner then has **1 second** to call `bind_with_process/3` or
`bind_with_handler/3` to register a receiver for that connection. If no binding happens within
1 second the connection is dropped and the owner receives `t:srt_server_conn_timeout/0`.

The registered receiver will receive `t:srt_data/0` and `t:srt_server_conn_closed/0` messages.

## Password Authentication

SRT supports password-based authentication. When using password authentication:
- Password must be between 10 and 79 characters long (SRT specification requirement)
- Empty string means no password authentication (default behavior)
- All connecting clients must provide the same password

A process starting the server will also receive the following notifications:
* `t:srt_server_conn/0` - a new client connection has been established
* `t:srt_server_conn_closed/0` - a client connection has been closed
* `t:srt_server_error/0` - server has encountered an error
* `t:srt_data/0` - server has received new data on a client connection

# `accept_mode`

```elixir
@type accept_mode() :: :accept_all | :whitelist | {:whitelist, [String.t()]}
```

# `connection_id`

```elixir
@type connection_id() :: non_neg_integer()
```

# `srt_data`

```elixir
@type srt_data() :: {:srt_data, connection_id(), data :: binary()}
```

# `srt_server_conn`

```elixir
@type srt_server_conn() ::
  {:srt_server_conn, connection_id(), stream_id :: String.t()}
```

# `srt_server_conn_closed`

```elixir
@type srt_server_conn_closed() :: {:srt_server_conn_closed, connection_id()}
```

# `srt_server_conn_timeout`

```elixir
@type srt_server_conn_timeout() ::
  {:srt_server_conn_timeout, connection_id(), stream_id :: String.t()}
```

# `srt_server_error`

```elixir
@type srt_server_error() :: {:srt_server_error, connection_id(), error :: String.t()}
```

# `t`

```elixir
@type t() :: pid()
```

# `add_stream_id_to_whitelist`

```elixir
@spec add_stream_id_to_whitelist(t(), String.t()) ::
  :ok | {:error, reason :: String.t()}
```

Adds a stream ID to the server's whitelist at runtime.

Once added, connections carrying this stream ID will be accepted and the owner will receive
`t:srt_server_conn/0`. Call `bind_with_process/3` or `bind_with_handler/3` to register
a receiver.

# `bind_with_handler`

```elixir
@spec bind_with_handler(t(), connection_id(), ExLibSRT.Connection.Handler.t()) ::
  {:ok, ExLibSRT.Connection.t()} | {:error, reason :: any()}
```

Spawns an `ExLibSRT.Connection` process backed by `handler` and binds it to a pending
connection.

Must be called within 1 second of receiving `t:srt_server_conn/0`.

# `bind_with_process`

```elixir
@spec bind_with_process(t(), connection_id(), pid() | nil) ::
  :ok | {:error, reason :: String.t()}
```

Registers the given process (defaults to `self()`) as the receiver for a pending connection.

Must be called within 1 second of receiving `t:srt_server_conn/0`, otherwise the connection
will have been dropped. Returns `{:error, reason}` if the connection ID is not found.

After a successful bind the receiver will receive `t:srt_data/0` and
`t:srt_server_conn_closed/0` messages for the connection.

# `child_spec`

Returns a specification to start this module under a supervisor.

See `Supervisor`.

# `close_server_connection`

```elixir
@spec close_server_connection(connection_id(), t()) ::
  :ok | {:error, reason :: String.t()}
```

Closes the connection to the given client.

# `read_socket_stats`

```elixir
@spec read_socket_stats(connection_id(), t()) ::
  {:ok, ExLibSRT.SocketStats.t()} | {:error, reason :: String.t()}
```

Reads socket statistics.

# `remove_stream_id_from_whitelist`

```elixir
@spec remove_stream_id_from_whitelist(t(), String.t()) ::
  :ok | {:error, reason :: String.t()}
```

Removes a stream ID from the server's whitelist at runtime.

After removal, new connections carrying that stream ID will be rejected.

# `start`

```elixir
@spec start(
  address :: String.t(),
  port :: non_neg_integer(),
  opts :: keyword()
) :: {:ok, t()} | {:error, reason :: String.t(), error_code :: integer()}
```

Starts a new SRT server outside the supervision tree, binding to given address and port.

One may usually want to bind to `0.0.0.0` address.

## Options

* `:password` - SRT passphrase for authentication. Must be between 10 and 79 characters long
  according to SRT specification. Empty string (default) means no password authentication.
* `:latency_ms` - SRT latency in milliseconds. Defaults to `-1`.
* `:accept_mode` - Controls how the server accepts connections. See
  [whitelist mode](#module-accepting-connections-whitelist-mode) and
  [accept-all mode](#module-accepting-connections-accept-all-mode) for details.
  Valid values are:
  * `:accept_all` - Accept all connections regardless of stream ID.
  * `:whitelist` - Whitelist mode with an empty initial whitelist.
  * `{:whitelist, stream_ids}` - Whitelist mode with pre-populated stream IDs.
  Defaults to `:whitelist`.
* `:owner` - The process that receives `t:srt_server_conn/0` notifications for every accepted
  connection, as well as `{:srt_server_rejected_client, stream_id}` when a connection is rejected.
  Defaults to `self()`.

# `start_link`

```elixir
@spec start_link(
  address :: String.t(),
  port :: non_neg_integer(),
  opts :: keyword()
) :: {:ok, t()} | {:error, reason :: String.t(), error_code :: integer()}
```

Starts a new SRT server binding to given address and port and links to current process.

One may usually want to bind to `0.0.0.0` address.

## Options

* `:password` - SRT passphrase for authentication. Must be between 10 and 79 characters long
  according to SRT specification. Empty string (default) means no password authentication.
* `:latency_ms` - SRT latency in milliseconds, used to set [`SRTO_LATENCY` flag](https://github.com/Haivision/srt/blob/master/docs/API/API-socket-options.md#srto_latency). Defaults to `-1` (meaning that `SRTO_LATENCY` flag is not set).
* `:accept_mode` - Controls how the server accepts connections. See
  [whitelist mode](#module-accepting-connections) for details.
  Valid values are:
  * `:accept_all` - Accept all connections regardless of stream ID.
  * `:whitelist` - Whitelist mode with an empty initial whitelist.
  * `{:whitelist, stream_ids}` - Whitelist mode with pre-populated stream IDs.
  Defaults to `:whitelist`.
* `:owner` - The process that receives `t:srt_server_conn/0` notifications for every accepted
  connection, as well as `{:srt_server_rejected_client, stream_id}` when a connection is rejected.
  Defaults to `self()`.

# `stop`

```elixir
@spec stop(t()) :: :ok | {:error, reason :: String.t()}
```

Stops the server.

Stopping a server closes all active connections.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
