Skip to content

SRT

media.play.srt

Transport

MPEG-TS over SRT/UDP; the client connects in caller mode to the stream’s dedicated port.

Supported codecs

Video

  • H.264
  • HEVC
  • AV1
  • JPEG 2000
  • MPEG-2 Video

Audio

  • AAC
  • MP2
  • MP3
  • AC-3
  • E-AC-3
  • SMPTE 302M

Other tracks

  • SCTE-35
  • KLV
  • ID3
  • tx3g
  • Teletext
  • DVB subtitles

This list describes Sapsan output; decoding support depends on the player. Tracks also need valid codec parameters for packaging in the selected container.

Sapsan serves a stream over SRT: each stream gets a dedicated UDP port that SRT clients connect to in caller mode.

AV1 in MPEG-TS uses the stream_type = 0x06 convention with the AV01 registration descriptor; the receiver must understand this form. This does not guarantee compatibility with every AV1-in-TS implementation. Opus is excluded from the list: recognizing or announcing a codec alone does not establish usable output, and the current path does not provide the required Opus TS/PES framing.

Configuration

Set these options through central in the streamer config.

streams:
  - name: tv1
    inputs:
    - udp: {host: 239.0.0.1, port: 5000}
    srt_play:
      port: 4010
      passphrase: verysecretpass

passphrase enables encryption; without it the stream is served unencrypted.

The srt_play section may carry an mpegts subsection — its own program number, track PIDs, and SDT for playback from this port only.

Client map

A port-wide passphrase is a single lock shared by everyone: everyone you gave the key to holds it. A client map defines personal locks: each viewer gets a secret of their own, and the session automatically receives an owner — the name of the matching record.

streams:
  - name: tv1
    inputs:
    - udp: {host: 239.0.0.1, port: 5000}
    srt_play:
      port: 4010
      clients:
        ivan:
          passphrase: ivan-personal-secret
        office:
          ips: [198.51.100.0/24]

A map record is a client name with two optional fields:

  • passphrase — the record's personal secret: when set, the handshake is encrypted and the viewer must present exactly this one; when unset, the record accepts unencrypted handshakes.
  • ips — an address filter: an address or subnet connections are accepted from. A missing or empty set does not restrict connections.

Admission follows from the record fields: an encrypted connection is accepted when its key material unfolds with the passphrase of one of the records with a password whose addresses include the viewer's address; an unencrypted one — by a passwordless record with a matching address, or by an open record (no password, no addresses) from any address. Records with and without a password coexist in one map: encryption is a property of the handshake, not of the port.

The viewer's session carries the owner — the name of the matching map record. For a delivery without a map, the owner comes from the user_id_<name> tag in labels; sessions of an untagged, map-less delivery stay without a subject.

The configuration is validated on save:

  • Identical passphrase values of two clients of one delivery are rejected: the secret is how a session identifies its client.
  • Overlapping ips sets of two clients are rejected: an address filter must belong to exactly one client.

In the management console the secret is generated by the server when a client is added. In YAML, an open record is a valid form of unrestricted access.

The viewer connects with their own secret:

ffplay "srt://server:4010?passphrase=ivan-personal-secret"

Handshake observability

A delivery with a client map accepts handshakes from the network, and its primary load is secret checking. The node counts handshakes as series in the node scrape (GET /streamer/api-v4/runtime/metrics):

Series What it counts
srt_handshake_attempts_total attempts that reached an admission decision
srt_handshake_secret_candidates_total secret candidates tried — the total number of key material checks
srt_handshake_bad_secret_total rejections: no candidate matched
srt_handshake_address_filter_rejects_total address-filter rejections
# a regular viewer spends a couple of candidates per attempt; brute force tries the whole map
rate(srt_handshake_secret_candidates_total[5m])
  / rate(srt_handshake_attempts_total[5m])

Playback

ffplay "srt://server:4010?passphrase=verysecretpass"

Next steps