manage channels.md

Create and manage channels

Channels are created with PUT /channels/{channel_id}/, where {channel_id} is the channel name you choose. The same request creates a channel that does not exist and replaces one that does, so there is no separate create endpoint and no generated identifier to keep track of.

Read How Beam channels work first if you have not picked a spec.type yet, because that choice constrains everything else in the body.

Read the interfaces first

Channel inputs and outputs point at real ports on the device, so start by asking the device what it has:

curl <BASE_URL>/interfaces/

The response groups interfaces by kind. This is a response from a VEGA-7010, abbreviated to the first two of its four slot ports, with the addresses replaced:

{
  "ip": [
    { "name": "lo", "type": "IP", "ipAddresses": ["127.0.0.1"], "displayName": "lo" },
    { "name": "eth0", "type": "IP", "ipAddresses": ["10.0.0.10"], "displayName": "eth0" },
    { "name": "eth1", "type": "IP", "ipAddresses": ["172.16.0.10"], "displayName": "eth1" }
  ],
  "sdi": [
    {
      "name": "slot_1_port_1",
      "type": "SDIASI",
      "url": "sdi://localhost/slot_1_port_1",
      "displayName": "Slot 1 / Port 1"
    },
    {
      "name": "slot_1_port_2",
      "type": "SDIASI",
      "url": "sdi://localhost/slot_1_port_2",
      "displayName": "Slot 1 / Port 2"
    }
  ],
  "asi": [
    {
      "name": "slot_1_port_1",
      "type": "SDIASI",
      "url": "asi://localhost/slot_1_port_1",
      "displayName": "Slot 1 / Port 1"
    },
    {
      "name": "slot_1_port_2",
      "type": "SDIASI",
      "url": "asi://localhost/slot_1_port_2",
      "displayName": "Slot 1 / Port 2"
    }
  ],
  "rf_demod": [],
  "rf_modulator": [],
  "st2110": []
}

What a device returns depends entirely on the hardware fitted to it. The device above has no satellite demodulator or modulator, so rf_demod and rf_modulator are empty. Another device will list different slots, different port counts, and different groups, which is why this call belongs at the start of any integration rather than in your notes.

Network transports take an interface name, such as eth0. Baseband and RF transports take the url exactly as returned.

Copy the url rather than composing it. The same physical port is listed under both sdi and asi with the same name, and only the scheme in the url distinguishes them. A name on its own does not identify a port.

Read the groups you need by key and ignore the rest, rather than assuming a fixed set. The groups a device returns can differ from the ones documented in the Channels API reference.

Create a channel

This request creates a contribution channel that takes a Serial Digital Interface (SDI) source, encodes it, and publishes it as a Secure Reliable Transport (SRT) listener that a remote decoder can connect to. It is created stopped, so nothing goes on air until you ask it to.

curl -X PUT <BASE_URL>/channels/news-contribution/ \
  -H "Content-Type: application/json" \
  -d '{
    "kind": "BeamChannel",
    "metadata": {
      "name": "news-contribution",
      "displayName": "News contribution"
    },
    "spec": {
      "type": "EncodingContribution",
      "state": "Stopped",
      "inputs": [
        {
          "type": "SDI",
          "name": "sdi-in",
          "transport": { "url": "sdi://localhost/slot_1_port_1" }
        }
      ],
      "transform": {
        "encoding": {
          "video": {
            "codec": "H264High",
            "videoFormat": "1920x1080p",
            "bitrate": 15000000
          },
          "audios": [
            { "codec": "AC3", "mode": "Stereo", "bitrate": 128000 }
          ]
        }
      },
      "outputs": [
        {
          "type": "SRTListener",
          "transport": { "interface": "eth0", "port": 9000 }
        }
      ]
    }
  }' 

The fields that are easy to get wrong:

The response is the full channel object, including the metadata.created timestamp and an initial status.

A 200 here means the device accepted the configuration, not that the channel is configured. Confirm the result:

curl <BASE_URL>/channels/news-contribution/

Read status.syncState. It reports Configuring while the device applies the change and Ok once the running configuration matches your spec. Anything else means the configuration was accepted but could not be applied, and status.syncError carries the detail.

Choosing between variants

The body above is one shape of channel. Use this table to find the shape you need, then adapt the example:

Your situation spec.type Body differences
Encoding a baseband source for onward contribution EncodingContribution Requires transform.encoding. Video codecs are the 4:2:2 and JPEG XS profiles, plus H264High and its variants.
Encoding a baseband source for delivery to viewers EncodingDistribution Requires transform.encoding. Video codecs are the delivery profiles: HEVCMain, HEVCMain10bit, H264High, H264Main, and MPEG2.
Encoding a baseband source into adaptive bitrate output EncodingStreaming Requires transform.abrEncoding instead of transform.encoding. The only output type is HttpStreaming.
Receiving a stream and putting it back to baseband ReceptionDecoding No transform. Outputs are SDI or Smpte2110.
Receiving a stream and passing it on untouched ReceptionGateway No transform. Outputs are the transport types, as for contribution.

A reception channel is considerably shorter, because there is nothing to encode. This one takes a multicast UDP source and decodes it out of an SDI port, and starts immediately:

curl -X PUT <BASE_URL>/channels/udp-to-sdi/ \
  -H "Content-Type: application/json" \
  -d '{
    "kind": "BeamChannel",
    "metadata": {
      "name": "udp-to-sdi",
      "displayName": "UDP to SDI decoder"
    },
    "spec": {
      "type": "ReceptionDecoding",
      "state": "Running",
      "inputs": [
        {
          "type": "UDP",
          "name": "udp-in",
          "transport": {
            "url": "udp://239.100.1.1:5001",
            "interface": "eth0"
          }
        }
      ],
      "outputs": [
        {
          "type": "SDI",
          "transport": { "url": "sdi://localhost/slot_1_port_1" }
        }
      ]
    }
  }' 

A UDP input needs both a url and an interface, because the device has to know which network port to join the multicast group on. Set unicast to true if the source is a unicast stream.

For the full list of input and output schemas, including SMPTE 2110 and satellite demodulator inputs, see the Channels API reference.

Encrypting an SRT output

To encrypt an SRT output, set encryptionStandard to AES128, AES192, or AES256, and supply a passphrase of at least 10 characters:

{
  "type": "SRTListener",
  "transport": {
    "interface": "eth0",
    "port": 9000,
    "encryptionStandard": "AES128",
    "passPhrase": "<PASSPHRASE>"
  }
}

passPhrase is optional while encryptionStandard is None, which is the default, and required as soon as it is anything else. A passphrase shorter than 10 characters is rejected.

Start, stop, and rename

PATCH /channels/{channel_id}/ handles the two changes you make most often. It accepts only the desired state and the display name, so use PUT for anything else.

Start a channel:

curl -X PATCH <BASE_URL>/channels/news-contribution/ \
  -H "Content-Type: application/json" \
  -d '{ "spec": { "state": "Running" } }'

Send "Stopped" in the same shape to take it off air. Rename it with the other half of the body:

curl -X PATCH <BASE_URL>/channels/news-contribution/ \
  -H "Content-Type: application/json" \
  -d '{ "metadata": { "displayName": "News contribution, main feed" } }'

Both fields are nested under spec and metadata respectively. A flat body such as {"state": "Running"} does not change anything, because neither key is recognised at the top level.

Renaming changes displayName only. metadata.name is fixed for the life of the channel, so a channel that needs a different identifier has to be recreated.

Delete a channel

curl -X DELETE <BASE_URL>/channels/news-contribution/

A successful delete returns 204 with no body. The device stops the underlying services before removing the channel. Errors during that cleanup are logged on the device but do not stop the channel being removed, so a 204 confirms the channel is gone rather than that everything behind it shut down cleanly.

What goes wrong

The request succeeded but nothing is on air. Check spec.state. A channel created with "state": "Stopped" stays stopped until you patch it. If it is Running, check status.syncState and status.syncError.

A codec value is rejected. The accepted video codecs depend on spec.type. HEVCMain is valid for EncodingDistribution and EncodingStreaming but not for EncodingContribution, which takes the 4:2:2 profiles. The accepted videoFormat values then depend on the codec you chose, and the interlaced formats are not available with the progressive-only codecs such as JPEG XS.

An audio bitrate is rejected. Audio bitrate is constrained by codec and mode together. AC3 with Stereo starts at 96000, while AC3 with Surround51 starts at 224000.

A PUT removed settings you did not send. PUT replaces the channel rather than merging into it. Fetch the channel, change what you need in the returned spec, and send the whole spec back.

The response is 422. The body contains a detail array, and each entry has a loc array giving the exact path to the offending field. Read loc before anything else, because it points straight at the field name.

The response is 503. The channel endpoints return 503 when the API cannot serve the request. Retry, and if it persists, check the device itself.

Where to go deeper