#[non_exhaustive]pub enum SessionEvent {
Established,
NewProgram {
program: ProgramId,
tracks: Vec<TrackSpec>,
},
Sample {
program: ProgramId,
track_id: u32,
retention: RetentionClass,
sample: Sample,
},
TracksChanged {
program: ProgramId,
tracks: Vec<TrackSpec>,
},
}std only.Expand description
What an IngestSession’s Stage::poll hands back to a driver.
#[non_exhaustive]: a later step (egress track-set negotiation, §1.3’s
upstream program-split) may still need a ProgramEnded variant —
SessionEvent::TracksChanged (issue #781) closed the mid-stream
track-set half of this gap, but this step does not add a variant it has
no correct producer for yet (this crate’s own precedent —
crate::byte_merge’s Hitless2022_7 note).
Variants (Non-exhaustive)§
This enum is marked as non-exhaustive
Established
The handshake finished: this session’s transport is usable and it is
now live. Exactly one of these per session lifetime — see
Establishment is ordinary driving.
Until it arrives the driver reports HealthState::Establishing;
after it, HealthState::Live.
§Why not called TracksResolved
transmux::DemuxEvent::TracksResolved { generation } already owns that
name for the analogous demux-side question, and this is deliberately
not a synonym for it: tracks here are a per-program fact carried by
SessionEvent::NewProgram (finding B5 — one connection, N programs),
whereas establishment is a per-connection fact. Folding tracks into
this variant would force a session ingesting an MPTS to nominate some
arbitrary program as “the one that resolved the connection”, and would
leave a session that has finished its handshake but not yet seen a PAT
with no way to say so. It carries no payload for the same
“no field without a correct producer” reason.
The two events do line up on the awkward case, though, and this is
where that lands: DemuxEvent::TracksResolved’s own docs note that a
container with no up-front track declaration (FLV/RTMP) legitimately
never emits it, and that the asymmetry “is for the media plane’s
ingress layer to handle explicitly (e.g. gating on the first
DemuxEvent::Sample)”. This variant is that explicit handling: an
RTMP session decides for itself when it is ready — gating on the first
sample, exactly as those docs suggest — and says so here.
NewProgram
A new program was discovered — mint a fresh Trunk for it. May be
the very first event a session ever produces, or arrive after many
samples for other programs already have — both are the same case;
see the module docs.
Fields
program: ProgramIdIdentifies this program for every subsequent
SessionEvent::Sample carrying it.
tracks: Vec<TrackSpec>The demuxed track specs for this program, so far. Reuses
transmux::TrackSpec rather than inventing a parallel type —
this crate’s established pattern (see crate::trunk::SegmentEntry’s
module doc for the same reuse-don’t-duplicate reasoning).
Sample
One decoded sample for track_id, belonging to program (must have
been announced via a prior NewProgram with this program — a
Sample for an unannounced program is a contract violation by the
IngestSession implementor, and a driver drops it rather than
panicking; see IngestDriver’s docs).
Fields
track_id: u32Track id within that program, matching
TrunkWriter::publish’s own track_id.
retention: RetentionClassWhich ring this sample’s track publishes into — the publisher
(ultimately, the IngestSession implementor) decides this, same
as any other TrunkWriter::publish caller.
TracksChanged
program’s track set changed mid-stream (issue #781) — e.g.
transmux’s PMT version diffing detects a broadcaster adding an audio
language. Must have been announced via a prior NewProgram with this
program, exactly like SessionEvent::Sample — a TracksChanged
for an unannounced program is the identical contract violation, and a
driver drops it the identical way (see IngestDriver’s docs); it
never mints a Trunk on its own.
§Why tracks is the complete replacement set, not a delta
A PMT carries the whole elementary-stream list on every version bump, not just what changed — there is no “here is the one track that was added” signal at that layer, only “here is the program’s full track list, as of now”. Carrying the complete set here mirrors that fact rather than fighting it, and buys two things a delta encoding cannot:
- Idempotence. Re-delivering the same
TracksChangedtwice (a retried demux pass, a duplicate event) leaves the trunk’s track set unchanged in content — replacing a set with an identical set is a no-op in substance, whereas replaying an “add track” delta twice would double-add it. - Immunity to delta-ordering bugs. A dropped or reordered
TrackAdded/TrackRemovedpair (exactly the demux-layer eventstransmuxalready emits — see below) can never leave a consumer’s view of the track set permanently wrong: the nextTracksChangedis a fresh, authoritative snapshot, not an increment on top of whatever state happened to accumulate.
A consumer that cares which track appeared or vanished diffs this
snapshot against the previous one it already holds (or against
crate::Trunk::tracks, which this event’s application updates) —
that comparison is the consumer’s to make, not this event’s to
pre-compute.
§Why this layer does not mirror transmux::DemuxEvent’s three events
transmux already emits DemuxEvent::TrackAdded/TrackRemoved/
TrackUpdated at the demux layer — finer-grained, delta-shaped
events aimed at a caller that wants to react to what changed. This
layer deliberately does not mirror that shape: IngestSession
implementors translate whatever demux-layer deltas they see into one
full snapshot per change, for the same reason SessionEvent::NewProgram
carries a full tracks: Vec<TrackSpec> rather than a “here is track
N” event per track — see the module docs.
§Scope: ingress→Trunk plumbing only
This variant and IngestDriver’s handling of it stop at storing
the new set on the program’s Trunk (see
crate::TrunkWriter::set_tracks). Deciding whether/when to admit a
newly-appeared track into an egress manifest (LL-HLS/DASH rendering)
is a separate, deliberate decision belonging to its own issue — not
something a track-set snapshot arriving at the Trunk should trigger
implicitly.
Trait Implementations§
Source§impl Clone for SessionEvent
impl Clone for SessionEvent
Source§fn clone(&self) -> SessionEvent
fn clone(&self) -> SessionEvent
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read more