Streams API
The stream methods read and modify the stream list of the configuration, start and stop streams, switch their inputs and report their status. Most of them are served on the POST /control/ entry point with the command name in cmd; the read-only status and info methods and the output group method are served on the path entry point. See How to call API methods for the entry points, authentication and roles. Every method on this page answers 200 with a JSON body: a failed command reports the failure inside the body, either as the value "er" under the command name or as an error field, never with an HTTP error status.
Stream configuration
Section titled “Stream configuration”A stream is a JSON object in the make_stream list of the configuration. The API stores the object as sent; only the fields below are read by the methods on this page, every other option is passed through to the stream when it starts. For the full option set see the stream configuration articles: SPTS Service Settings, SPTS Backup Settings and MPTS General Settings.
{ "id": "a001", "name": "Channel 1", "type": "spts", "enable": true, "input": [ "udp://239.255.1.1:1234" ], "output": [ "udp://239.255.2.1:1234" ]}id- string. Unique stream identifier, theidof every method below. A stream stored without anidcannot be addressed afterwards.name- string, required to start the stream. A stream without a name is stored but not started.type- string,sptsormpts. Selects the pipeline and the version fields the API maintains (see below).enable- boolean.truestarts the stream when it is set; a stream withfalseor without the field is stored only.input- array, required to start the stream. Each item is an URL string or an object with anurlfield and further options. An item whose scheme is not a known input kind is logged and skipped.output- array, optional. Same item forms asinput.backup_type- string, optional.activewhen absent;passiveanddisableare the modes in which Switch active input works.no_event- boolean, optional.truedisables statistics collection for the stream, so Get stream status reportsmonitoring disabled.
Table version fields: set-stream maintains the PSI table version numbers inside the stored object, so that players notice a changed configuration. For spts streams pmt_version and sdt_version are set to 1 on the first save and incremented modulo 32 on every following save; for mpts streams pat_version, cat_version, sdt_version and nit_version are set to 0 on the first save and incremented modulo 32 afterwards. Send the object back as it was read, so that the counters continue.
Get stream configuration
Section titled “Get stream configuration”Request: POST /control/. Control and observer.
{ "cmd": "get-stream", "id": "a001"}id- string, required. Stream identifier.
Response:
{ "get-stream": "ok", "stream": { "id": "a001", "name": "Channel 1", "type": "spts", "enable": true, "input": [ "..." ] }}stream- the stored stream configuration object.
Unknown identifier:
{ "get-stream": "er", "error": "stream not found" }Get stream info
Section titled “Get stream info”Request: GET /api/stream-info or GET /api/stream-info/{id}. Control only; an observer receives 404.
Without an identifier the reply lists every stream:
{ "instance": "server-1", "streams": [ { "id": "a001", "name": "Channel 1", "type": "spts", "enable": true, "input": [ "..." ] } ]}instance- theinstance_namesetting, or the host name of the server when the setting is not defined.streams- array of the stored stream configuration objects,[]when there are none.
With an identifier the reply is the stored stream configuration object itself:
{ "id": "a001", "name": "Channel 1", "type": "spts", "enable": true, "input": [ "..." ] }Unknown identifier:
{ "error": "stream not found" }Create or update stream
Section titled “Create or update stream”Request: POST /control/. Control only.
{ "cmd": "set-stream", "id": "a001", "stream": { "id": "a001", "name": "Channel 1", "type": "spts", "enable": true, "input": [ "udp://239.255.1.1:1234" ] }}id- string, optional. Identifier of the stream to replace. When a stored stream has this identifier it is stopped and removed from the list before the new object is inserted; when none has it, the new object is added. Withoutidthe object is always added, so repeating such a request stores a second object with the samestream.id.stream- object, required. The stream configuration; its ownidfield is the identifier the stream is stored under, so keep it equal toid. The handler does not check that the two match.gid- number, optional. Identifier generator counter of the interface: when present it is stored asgidin the configuration and echoed in the notification, so that every interface client continues the same sequence.
Response:
{ "set-stream": "ok" }Without the stream field the reply is { "set-stream": "er" } and nothing changes.
Side effects:
- The stream object is appended to the end of the
make_streamlist, so a replaced stream changes its position. - The table version fields are set or incremented as described in Stream configuration.
- For
mptsstreams the object is registered with the MPTS registry under itsid. - With
enableset totruethe stream is started. A start failure (missingname, emptyinput, another running stream with the sameid) is written to the log; the reply is still"ok"and the object is saved. - The configuration is saved.
- WebSocket clients receive one or two notifications. When an existing stream was replaced:
{"scope": "set-stream", "stream": {"id": "a001", "remove": true, "up": true}}, whereupistruefor a replacement andfalsefor a removal. Then, for the inserted object:{"scope": "set-stream", "gid": 466561, "stream": { ... }}with the stored object including the version fields;gidis absent when the configuration holds none.
Delete stream
Section titled “Delete stream”Request: POST /control/. Control only.
{ "cmd": "set-stream", "id": "a001", "stream": { "remove": true }}id- string, required. Identifier of the stream to delete.stream.remove- boolean,true. Other fields ofstreamare not stored;stream.enableset totruestill triggers a start attempt of the removal object, which fails with a log line.
Response:
{ "set-stream": "ok" }The running stream is stopped, the object is removed from the make_stream list, an mpts stream is unregistered from the MPTS registry, the configuration is saved and WebSocket clients receive {"scope": "set-stream", "stream": {"id": "a001", "remove": true, "up": false}}. An unknown id changes nothing and is still answered "ok".
Toggle stream
Section titled “Toggle stream”Turn a stream on or off. Request: POST /control/. Control only.
{ "cmd": "toggle-stream", "id": "a001"}id- string, required. Stream identifier.
Response:
{ "toggle-stream": "ok" }Unknown identifier:
{ "toggle-stream": "er", "error": "stream not found" }Side effects: enable is inverted in the stored object (a missing enable becomes true); an enabled stream is started, a disabled one is stopped; the object moves to the end of the make_stream list; the configuration is saved; WebSocket clients receive {"scope": "set-stream", "stream": { ... }} with the updated object.
Restart stream
Section titled “Restart stream”Request: POST /control/. Control only.
{ "cmd": "restart-stream", "id": "a001"}id- string, required. Stream identifier.
Response:
{ "restart-stream": "ok" }Unknown identifier:
{ "restart-stream": "er", "error": "stream not found" }An enabled stream is stopped and started again from its stored configuration. A disabled stream is left alone and still answered "ok". The configuration is not changed and no notification is sent.
Check stream
Section titled “Check stream”Runtime status of a running stream. Request: POST /control/. Control and observer.
{ "cmd": "check-stream", "id": "a001", "status": true}id- string, required. Stream identifier. The stream must be running: a disabled stream is answeredstream not found.status- boolean, optional.trueadds thestatusobject to the reply.eit- boolean, optional. Accepted, but the stream keeps no EIT data, so the reply never carries aneitfield.
Response:
{ "check-stream": "ok", "status": { "active_input": 1, "onair": true, "input": [ { "bitrate": 4200, "packets": 27931, "scrambled": false, "cc_error": 0, "pes_error": 0, "sc_error": 0, "pcr_error": 0 } ] }}active_input- number of the input selected as active,1for the first input.0while none is selected: before the first analyzer report and, with the default backup type, while no input is on air.onair-truewhile the active input works without errors.input- array indexed by input number with the last analyzer sample of each input:bitratein Kbit/s,packetscounted in the sample,scrambled, and thecc_error,pes_error,sc_errorandpcr_errorcounters of the sample. An input that is starting or was stopped holds{"bitrate": 0}only; an input that was never started has no entry. The value is a JSON array while the entries are numbered from1without gaps; otherwise it is a JSON object with the input numbers as string keys, for example{"0": {"bitrate": 0}, "1": { ... }, "2": { ... }}after Switch active input was called while no input was on air.no_active_input-truewhile no input is on air; absent otherwise.
The status fields are filled for spts streams whose inputs run. An spts stream without outputs is started on demand, when the first HTTP client connects, and until then keeps the initial values active_input: 0, onair: false, input: []; an mpts stream keeps them always.
Unknown or not running identifier:
{ "check-stream": "er", "error": "stream not found" }Get stream status
Section titled “Get stream status”Statistics of a running stream from the monitoring module. Request: GET /api/stream-status/{id} with an optional query ?t={time}. Control only; an observer receives 404.
id- string, required in the path. Stream identifier; the stream must be running.t- number, optional query parameter.1(default) returns the statistics of the last completed monitoring interval,0the latest analyzer sample. Any other number is answered{"error": "not implemented"}; a value that is not a number counts as1.
The monitoring interval is the tsdb_interval setting, 60 seconds when not defined.
Response:
{ "instance": "server-1", "name": "Channel 1", "input_id": 1, "timestamp": 1758240000, "active": true, "onair": true, "sessions": 0, "pes_error": 0, "sc_error": 0, "cc_error": 0, "sync_error": 0, "bitrate": 4200, "video_count": 1, "audio_count": 1}instance- theinstance_namesetting; absent when the setting is not defined.name- stream name.input_id- number of the input on air,1for the first input.0in an interval report of an inactive stream.timestamp- Unix time. Fort=1the end of the reported interval, fort=0the current time.active-trueif the stream is active.falsewhen it works on demand and is inactive, and in an interval report with no collected samples; theninput_id,sessionsand every counter are0.onair-trueif the active input works without errors.sessions- number of active client sessions on the stream.pes_error- PES errors as a percentage of the PES packets, over the interval fort=1or in the latest sample fort=0.sc_error- scrambled TS packets as a percentage of all TS packets, over the same span. If the stream is protected by a conditional access systemsc_errorandpes_errorare greater than0; a stream descrambled with a wrong key showssc_errorequal to0andpes_errorgreater than0.cc_error- continuity counter errors, summed over the interval fort=1, of the latest sample fort=0. Caused by packet loss or duplication.sync_error- not filled by the stream analyzer, always0.bitrate- Kbit/s. Average over the interval fort=1, the latest sample fort=0.video_count- number of video streams.audio_count- number of audio streams.
Error replies, all with status 200:
{"error": "stream id not defined"}- no identifier in the path.{"error": "stream not found"}- the stream is not running (unknown identifier or disabled stream).{"error": "monitoring disabled"}- the stream has no monitoring slot:mptsstreams and streams withno_eventset.{"error": "not implemented"}-tis a number other than0and1.
Switch active input
Section titled “Switch active input”Choose the active input. Works only for streams with the backup type passive or disable. Request: POST /control/. Control only.
{ "cmd": "set-stream-input", "id": "a001", "input": 2}id- string, required. Stream identifier; the stream must be running.input- number, optional. Input number, numbering starts from 1; a numeric string is accepted. When the field is absent or names an input that is not in the stream’sinputlist, the input after the active one is chosen, wrapping around to the first.
Response:
{ "set-stream-input": "ok" }A stream that is not running, or whose backup_type is neither passive nor disable, is answered { "set-stream-input": "er" } without an error field.
The chosen number is compared with active_input of the stream status (see Check stream). When they differ, the input numbered active_input is destroyed and the chosen input is started unless it already runs; when they are equal nothing changes. While no input is on air active_input is 0, so the running input keeps running, the chosen one is started next to it and status.input gets a "0" entry. The configuration is not changed and the command sends no notification of its own; the analyzer’s regular stream_event messages, one per running input, show which inputs run.
Set stream image
Section titled “Set stream image”Push a picture URL for a stream to the connected interface clients. Request: POST /control/. Control only.
{ "cmd": "set-stream-image", "id": "a001", "url": "http://server/images/a001.png"}id- string, required. Stream identifier; the stream must exist in the configuration, running or not.url- string, optional. Sent to the clients assrc; absent in the notification when omitted.
Response:
{ "set-stream-image": true }Unknown identifier:
{ "set-stream-image": false, "error": "stream not found" }The only effect is the WebSocket notification {"scope": "stream_image", "channel_id": "a001", "src": "http://server/images/a001.png"}. Nothing is stored. The Channel Screenshots on Dashboard script uses this method to put screenshots on the stream tiles.
Output group
Section titled “Output group”Create, replace or remove a named output group in the output list of the configuration. Request: POST /api/output-group to create a group, POST /api/output-group/{name} to replace or remove the group with that name. Control only; an observer receives 404.
{ "group": { "name": "Cable head-end" }, "remove": false}namein the path - string. Name of an existing group;group not foundwhen no stored group has it.group- object. The group to store;nameis the only field the handler reads, the rest is stored as sent. Required to create or replace a group.remove- boolean, optional.truetogether with a name in the path removes that group.
Response:
{ "ok": true }Error replies, all with status 200:
{"error": "invalid data"}- the body is not valid JSON.{"error": "group not found"}- the name in the path matches no stored group.{"error": "group name already exists"}- another stored group already hasgroup.name: a duplicate name on create, or a rename onto an existing name. Replacing a group under its own name passes.
Side effects: the output list of the configuration is updated (a new group is appended, a replaced group keeps its position, the list is dropped when the last group is removed), the configuration is saved and WebSocket clients receive {"scope": "post-output-group", "index": 0, "remove": false, "group": { ... }}, where index is the zero-based position of the replaced or removed group and absent for a new one, and remove and group echo the request fields and are absent when the request did not carry them. Astra stores the groups for the interface; no stream or output is started from them.