Pull-input Streams
A normal stream is push-in: your encoder opens RTMP/E-RTMP, SRT, or WHIP to FrameWorks and uploads media. A pull-input stream is the inverse: FrameWorks stores an upstream URL, then a media edge opens that source when playback needs it.
The payoff is operational: you can onboard venue cameras, contribution feeds, and existing origins without asking every source to become a FrameWorks encoder. Pull input also composes with the rest of the platform — playback access control, DVR, clips, thumbnails, analytics, and multistreaming all attach to the stream once media is active.
Use pull-input streams when:
- The source is an existing camera, encoder, or origin server that cannot push to FrameWorks.
- A venue sends you an SRT/RIST contribution feed.
- You need to restream an HLS or MPEG-TS source.
- You run self-hosted edge nodes that can reach private cameras or LAN/VPC sources.
Supported Source Schemes
Section titled “Supported Source Schemes”| Scheme | Mist input | Notes |
|---|---|---|
rtsp:// | RTSP | Basic-auth in URI accepted; rtsps:// is not supported yet. |
srt:// | SRT | Stream ID and passphrase use standard SRT URL params. |
rist:// | RIST | MPEG-TS over RIST. |
dtsc:// | DTSC | Pull from another Mist node. Useful for bridging self-hosted media planes. |
https://.../*.m3u8 | HLS | Matched by suffix. |
https://.../*.ts | TS | Single-file TS pulls; for live TS-over-HTTP, prefer HLS or tsudp://. |
https://.../*.mkv | EBML | Includes WebM (.webm). Useful for VOD-as-live and some WHIP recordings. |
tsudp://host:port | TS over UDP | Unicast or multicast. Private and multicast destinations need an opted-in edge cluster. |
RTMP pull is not supported. RTMP stays push-only. If you need to pull from an RTMP source, run a
converter such as FFmpeg, MistServer, or srt-live-transmit and pull its SRT, RIST, RTSP, or HLS
output instead.
Create a Pull Stream
Section titled “Create a Pull Stream”In the dashboard, create a stream and choose Pull as the ingest mode. Provide the upstream source URI and keep the source enabled if it should start when viewers request playback.
Through GraphQL, use createStream with ingestMode: PULL and pullSource:
mutation CreatePullStream($input: CreateStreamInput!) { createStream(input: $input) { __typename ... on Stream { id playbackId ingestMode pullSource { sourceUriRedacted enabled class allowedClusterIds } } }}{ "input": { "name": "Lobby Camera", "ingestMode": "PULL", "pullSource": { "sourceUri": "rtsp://camera.example.net/live", "enabled": true, "allowedClusters": { "clusterIds": [] } } }}The source URI is stored encrypted and returned only in redacted form. For public sources,
allowedClusters.clusterIds: [] means any media cluster may run the pull. Set cluster IDs to
pin a public source to a specific cluster set.
Private Upstreams on Self-hosted Edges
Section titled “Private Upstreams on Self-hosted Edges”Private literals require two pieces of configuration:
- The target media cluster must opt in with
allow_private_pull_sources: true. - The pull stream must explicitly pin itself to that cluster with
allowedClusters.clusterIds(GraphQL) orallowed_cluster_ids(bootstrap).
clusters: warehouse-edge: name: Warehouse Edge type: edge owner_tenant: acme roles: [media] allow_private_pull_sources: trueThen create the pull stream with the placement pin:
{ "input": { "name": "Warehouse Camera", "ingestMode": "PULL", "pullSource": { "sourceUri": "rtsp://192.168.10.50/live", "enabled": true, "allowedClusters": { "clusterIds": ["warehouse-edge"] } } }}This protects platform-managed clusters from trying to reach sources they cannot access and keeps private-source placement constrained to edge nodes you operate.
| Deployment shape | Result |
|---|---|
| Platform cluster, public source URI | Allowed. |
| Platform cluster, private literal source URI | Rejected. |
| Self-hosted edge with opt-in + placement pin | Allowed and routed only to the pinned eligible media clusters. |
| Hostname resolving to private IP from an edge | Treated as public at validation; DNS reachability is operator-owned. |
Runtime Behavior
Section titled “Runtime Behavior”Pull streams are on-demand:
- A viewer requests
/play/{playback_id}. - Foghorn routes the viewer to an eligible media edge, even if the stream is currently inactive.
- MistServer starts the
pull+stream and asks Foghorn for the source. - Foghorn ignores untrusted fallback query params and resolves the stored source URI from Commodore.
- The first edge pulls upstream media; later viewers prefer in-cluster DTSC fanout once available.
- When the last viewer leaves, MistServer drops the upstream after the standard grace period.
Idle pull streams do not fetch from the upstream and do not accrue live processing or viewer costs. Once active, metering is the same as push streams: viewer minutes, egress, transcoding, recording, and storage apply normally.
Resolution Events
Section titled “Resolution Events”Every STREAM_SOURCE evaluation records the resolution outcome. The dashboard shows the latest
events on the stream setup panel, and GraphQL exposes the same feed:
query PullSourceEvents($id: ID!) { stream(id: $id) { ... on Stream { ingestMode recentPullSourceEvents(limit: 10) { eventKind detail createdAt } } }}eventKind is one of resolved, not_found, disabled, blocked_uri,
private_not_allowed, commodore_error, or foghorn_base_unresolved. These are source
resolution events: they explain whether Foghorn handed MistServer a source. Upstream
connect/disconnect/retry telemetry depends on MistServer emitting additional trigger types.
Failure Modes
Section titled “Failure Modes”- Upstream unreachable - The Mist input exits. The next viewer triggers a fresh pull attempt.
- Two viewers arrive at once - More than one edge can briefly pull from the upstream before fanout takes over.
- Source URI changed - Update the pull source from the dashboard or GraphQL. Operator-managed pull streams can also be updated by re-running bootstrap with the new URI. Active sessions reconnect against the new origin after the media plane sees the updated source.
- Source sends silence or black - FrameWorks does not synthesize fallback media; viewers see what the upstream sends.
Feature Parity
Section titled “Feature Parity”Once media is active, pull streams behave like push streams:
- Playback access control can gate viewers with JWT or webhook policies.
- Recording and DVR work with the same stream-level recording flag.
- Multistreaming can push the pulled source onward to RTMP targets.
- Thumbnails and previews use the same generation pipeline.
For a lower-level service map, see the architecture note in
docs/architecture/pull-streams.md.