A continuous stream is payload data that flows without interruption — imaging, video, instrument data — which the MCS carries and archives but never decodes. The gateway publishes the stream in segments, JetStream archives them, and downstream chains subscribed to the stream process the content. The MCS measures the quality of each stream (rate, bytes, lost segments) as ordinary measures, so that procedures and alarms can use them.
Declaring a stream#
Streams are declared in the catalogue by the standard stream component: one identifier and a
nominal rate per stream. Its instances are the streams (enum stream.stream_id). A stream is
started and stopped by ordinary telecommands of this component, addressed to the stream:
components:
stream:
streams:
camera: {rate: 256 kbit/s}
telecommands:
start_stream:
verify: [echo]
stop_stream:
verify: [echo]
alarms:
stream_gap:
severity: warning
when: delta(gaps, 30 s) > 0step "Start the camera"
uses sat: platform-v3
send start_stream to sat.stream[camera]
expect sat.stream[camera].rate > 0 within 30 sThe stream component declares neither instances nor measures: both are generated. See
Files and Streams.
Carrying the segments#
The gateway publishes each segment raw on stellar.stream.<target>.<stream_id>, with two headers:
| Header | Meaning |
|---|---|
Stellar-Ground-Time | Ground reception time (RFC 3339) |
Stellar-Stream-Seq | Segment number, from 1, consecutive as long as nothing is lost |
In the SDKs, a gateway calls publish_segment(target, stream, seq, segment, ground_time), in Rust
(Downlink::publish_segment) as in Python. Its NATS credentials allow it to publish the streams of
its targets only. See Writing a Gateway.
The archive#
The JetStream stream STREAMS archives every segment. Its retention is set in the global
configuration:
archive:
streams:
max_age: 30d
max_bytes: 2TBThe first limit reached applies; the oldest segments go first. The reconciler applies the
retention when it starts. JetStream reserves max_bytes on the disk of the server: when it
cannot, the archive is bounded by max_age only, and the reconciler logs a warning.
Quality of a stream#
The transfer manager measures each stream on the segments it receives, and publishes three
measures of the stream component every second, per stream:
| Measure | Meaning |
|---|---|
stream[camera].rate | Throughput in bit/s over the last 5 seconds |
stream[camera].bytes | Bytes received |
stream[camera].gaps | Segments lost, counted from the jumps of Stellar-Stream-Seq |
A sequence number that goes back is a restart of the numbering, not a gap. When a stream stops, a rate of 0 is published once.
These measures are published as raw values on stellar.tm.decoded.<target>, like those of a
driver: the compute stage, the current value table, the procedures and the alarms treat them as
any measure. They are measures of the platform, not of the drivers: they do not count in the
coverage a driver must declare.
The catalogue can declare derived measures and alarms on them, as stream_gap above, which raises
a warning as soon as a segment was lost in the last 30 seconds.
stellar watch sat1-fm 'stream[camera].rate' 'stream[camera].gaps'Simulated streams#
The simulator produces the segments of a stream on board at its nominal rate,
once a telecommand marked stream: start is sent to it, until one marked stream: stop. Outside
a pass, the segments are lost. Its stream_gap verb ({stream, segments}) drops the next
segments of a stream, to exercise the gaps measure and its alarms:
nats request stellar.ctl.rpc.gateway.sim-gw-1.stream_gap '{"stream": "camera", "segments": 5}'See also#
- Output Connectors: the
streamsdata kind. - NATS and JetStream: streams and retention.