pub struct HlsOrigin { /* private fields */ }std only.Expand description
The LL-HLS origin ServedEgress: renders playlists and resolves
blocking-reload/part-availability requests for one stream, backed by a
shared Trunk. See this module’s own doc for exactly what comes
straight from the Trunk and what needs the small synced Window.
Implementations§
Source§impl HlsOrigin
impl HlsOrigin
Sourcepub fn builder(trunk: Arc<Trunk>) -> HlsOriginBuilder
pub fn builder(trunk: Arc<Trunk>) -> HlsOriginBuilder
Start building an HlsOrigin over trunk — see HlsOriginBuilder
for the required fields (target_duration_secs/window_segments),
the container choice, and how to opt into LL-HLS.
Sourcepub fn set_init(&self, bytes: impl Into<Bytes>)
pub fn set_init(&self, bytes: impl Into<Bytes>)
Store the init segment bytes — see this module’s doc for why an init
segment is not something any Trunk ring holds.
Documented no-op under Container::MpegTs: this origin’s
MpegTs grammar has no init resource and never emits #EXT-X-MAP
by default (see Container’s own doc), so bytes stored here are
never advertised or served in that mode. The method stays callable
regardless of container so a caller sharing one code path across
both (e.g. a segmenter that always calls set_init once available)
does not need to branch on which container it configured.
Under Container::Fmp4 the init segment is also parsed for its
tracks, from which the master playlist’s CODECS is derived (see
Self::master_playlist); bytes that do not parse (or a track whose
codec string cannot be built) make CODECS unknown (omitted, and any
value from an earlier init is dropped), never guessed at.
Sourcepub fn set_track_specs(&self, specs: &[TrackSpec]) -> Result<(), Error>
pub fn set_track_specs(&self, specs: &[TrackSpec]) -> Result<(), Error>
Tell the origin which tracks it serves, so the master playlist can
carry CODECS (RFC 8216 §4.3.4.2: every EXT-X-STREAM-INF SHOULD) —
derived from each track’s codec config with the RFC 6381 builders
transmux uses for DASH. Opaque data/subtitle tracks have no codec
string and are left out. Self::set_init does this itself for
fMP4; call this for a Container::MpegTs origin, whose segments
carry no init segment to read the codecs from.
§Errors
The transmux error for a track whose codec string cannot be built
(for example a malformed AAC esds); CODECS is then left as it was.
Sourcepub fn set_detected_closed_captions(&self, detected: Vec<InstreamId>)
pub fn set_detected_closed_captions(&self, detected: Vec<InstreamId>)
Record the caption streams the video is now known to carry. The next
master playlist advertises exactly these, one
EXT-X-MEDIA TYPE=CLOSED-CAPTIONS per stream in group
CLOSED_CAPTIONS_GROUP_ID, and every variant references the group.
An empty list means the video was scanned and carries none: the master
then states CLOSED-CAPTIONS=NONE on every variant (RFC 8216bis
section 4.4.6.2). Until this is called the master claims nothing either
way, unless HlsOriginBuilder::closed_captions_none is set.
Sourcepub fn set_declared_closed_caption_languages(
&self,
languages: Vec<(InstreamId, String)>,
)
pub fn set_declared_closed_caption_languages( &self, languages: Vec<(InstreamId, String)>, )
Record the BCP 47 LANGUAGE the stream declares for each caption
stream (the ATSC caption_service_descriptor in the PMT). A rendition
takes it unless a ClosedCaptionDecl override names a language.
Sourcepub fn set_subtitle_renditions(
&self,
decls: Vec<SubtitleRenditionDecl>,
) -> Result<(), HlsOriginBuildError>
pub fn set_subtitle_renditions( &self, decls: Vec<SubtitleRenditionDecl>, ) -> Result<(), HlsOriginBuildError>
Replace the declared WebVTT subtitle renditions after construction, for
a host that learns them only once the stream is seen (for example from
a teletext descriptor). The next master playlist advertises exactly
these in group SUBTITLES_GROUP_ID; an empty list removes the group.
§Errors
The same HlsOriginBuildError variants as
HlsOriginBuilder::subtitle_renditions at build(); the previous
declarations are kept on error.
Sourcepub fn master_playlist(
&self,
media_playlist_name: &str,
) -> Result<String, HlsMasterError>
pub fn master_playlist( &self, media_playlist_name: &str, ) -> Result<String, HlsMasterError>
The master playlist for this origin, pointing at media_playlist_name:
one #EXT-X-STREAM-INF whose BANDWIDTH is the highest segment
bitrate this origin has published (RFC 8216 §4.3.4.2: an upper bound
of the peak segment bitrate, measured as segment bytes over its
duration, rounded up) or the operator-declared bandwidth, whichever is
larger. Returns HlsMasterError::BandwidthUnknown until a segment
with a measurable duration has closed and no declared bandwidth was
configured.
§Errors
HlsMasterError::BandwidthUnknown when no measurable segment has
been published and no declared bandwidth was configured;
HlsMasterError::BandwidthOverflow when the measured BANDWIDTH
does not fit the u32 of a master playlist variant;
HlsMasterError::Render when the playlist cannot be rendered.
Sourcepub fn master_playlist_with_iframes(
&self,
media_playlist_name: &str,
iframe_playlist_name: &str,
) -> Result<String, HlsMasterError>
pub fn master_playlist_with_iframes( &self, media_playlist_name: &str, iframe_playlist_name: &str, ) -> Result<String, HlsMasterError>
Like Self::master_playlist, but additionally advertises an
#EXT-X-I-FRAME-STREAM-INF variant pointing at
iframe_playlist_name when an I-frame playlist is currently
available for this origin (fMP4, a video track, and at least one
usable entry with no mid-stream gap). The plain variant is unchanged.
§Errors
As for Self::master_playlist.
Sourcepub fn instance(&self) -> u64
pub fn instance(&self) -> u64
This origin’s instance token: a number that differs for every origin
built, in this process and across restarts (see
HlsOriginBuilder::instance), and is part of every resource name
served immutable — init-{track}-{instance}-{generation}.mp4,
seg-{track}-{instance}-{msn}.{ext},
part-{track}-{instance}-{msn}.{idx}.{ext}. A name therefore maps to
one origin’s bytes for ever: a reconnect (new Trunk, numbers
restarting, possibly a different SPS/ASC), a process restart with no
DVR, a replacement origin reusing the open segment’s number — none can
put new bytes under a name a cache may already hold. Playlists name
these URIs, so players are unaffected. A request carrying another
instance’s token is NotFound. The unnamed legacy forms
(seg-{track}-{msn}, part-{track}-{msn}.{idx}, used by DASH/Smooth
templates that cannot carry the token) still resolve but are
CachePolicy::NoCache; the bare init-{track}.mp4 is the current
init, also CachePolicy::NoCache.
Sourcepub fn iframe_playlist_name(&self, track_id: TrackId) -> String
pub fn iframe_playlist_name(&self, track_id: TrackId) -> String
The wire name of this origin’s I-frame playlist for track_id.
Sourcepub fn init_name(&self, track_id: TrackId, generation: Generation) -> String
pub fn init_name(&self, track_id: TrackId, generation: Generation) -> String
The wire name of init generation generation for track_id.
Sourcepub fn iframe_segment_name(
&self,
track_id: TrackId,
seq: SegmentSeq,
ext: &str,
) -> String
pub fn iframe_segment_name( &self, track_id: TrackId, seq: SegmentSeq, ext: &str, ) -> String
The wire name of the I-frame (trick-play) resource for track_id’s
segment seq (issue #1422): iframe-seg-{track}-{instance}-{seq}.{ext},
the same grammar as segment_name but under the
IFRAME_SEGMENT_PREFIX prefix, so the bytes it resolves to are
always the stored segment bytes and never the emsg-spliced ones.
Sourcepub fn media_sequence_offset(&self) -> u64
pub fn media_sequence_offset(&self) -> u64
The offset added to every Media Sequence Number this origin shows (see
HlsOriginBuilder::media_sequence_offset): the number in a segment’s
URI/playlist is this plus its origin sequence number
(ClosedSegment::sequence_number).
Sourcepub fn next_media_sequence(&self) -> u64
pub fn next_media_sequence(&self) -> u64
The Media Sequence Number the next closed segment will be shown with (last closed segment + 1, plus the configured offset).
A fresh Trunk numbers its segments from 1 again, so an origin
replacing this one over a new Trunk (a reconnect) must pass
next_media_sequence() to
HlsOriginBuilder::media_sequence_offset: the new origin’s first
segment (sequence number one) is then shown one above this value — the
number this origin’s open segment was shown with is skipped, since
its parts were already served — and the Media Sequence Number clients
see keeps increasing (RFC 8216bis §6.2.2).
Sourcepub fn http_priority(&self, request: &HlsRequest) -> HttpPriority
pub fn http_priority(&self, request: &HlsRequest) -> HttpPriority
HTTP Priority signalling for request (RFC 8216bis §6.2.6): the
urgency the adapter should attach to the response. Playlists get
urgency 1, parts and segments urgency 2.
Sourcepub fn target_duration_violations(&self) -> u64
pub fn target_duration_violations(&self) -> u64
Number of segments whose (rounded) duration exceeded the frozen
EXT-X-TARGETDURATION after first publication — a conformance
degradation count (RFC 8216 §4.3.3.1).
Sourcepub fn published_target_duration(&self) -> Duration
pub fn published_target_duration(&self) -> Duration
The EXT-X-TARGETDURATION this origin’s Media Playlists carry (or will
carry): the frozen value once published, otherwise the largest of its
own, its longest segment so far and its sibling renditions’. Unlike a
render it never freezes the value. RFC 8216bis section 6.2.5.2 measures
a blocking reload’s patience in these.
Sourcepub fn set_part_target_ms(&self, ms: u32)
pub fn set_part_target_ms(&self, ms: u32)
Raise this origin’s PART-TARGET to ms when that exceeds the
configured part target. An audio rendition whose frames do not divide
the part target needs a Part Target Duration of a whole number of
frames, because RFC 8216bis §4.4.4.9 requires every Partial Segment to
be no longer than it. Has no effect on a classic-HLS origin.
Sourcepub fn set_rendition_siblings(&self, siblings: Vec<RenditionSibling>)
pub fn set_rendition_siblings(&self, siblings: Vec<RenditionSibling>)
Replace the sibling renditions whose live edge this origin reports.
Sourcepub fn current_live_edge(&self) -> (u64, Option<u64>)
pub fn current_live_edge(&self) -> (u64, Option<u64>)
Snapshot of this origin’s current live edge as (LAST-MSN, LAST-PART),
suitable for an #EXT-X-RENDITION-REPORT (RFC 8216bis §4.4.5.4).
Drains this origin first and queries only this origin’s own Trunk,
so callers never hold another origin’s lock.
Sourcepub fn init_bytes(&self) -> Option<Bytes>
pub fn init_bytes(&self) -> Option<Bytes>
The fMP4 init segment bytes, if set.
Sourcepub fn closed_segments(&self) -> Vec<ClosedSegment>
pub fn closed_segments(&self) -> Vec<ClosedSegment>
A snapshot of this origin’s currently-advertised closed segments
(drains the cursor first, same as render_playlist) — ascending by
sequence number.
Exists for a caller that needs to merge this origin’s live window
with a different source of segments over the same numbering
(multimux’s DVR archive, issue #900: catch-up serving must present
one continuous playlist spanning the archive and the still-live
tail that hasn’t been archived yet). Reuses the one cursor drain
already maintains rather than making the caller open a second
cursor on the same Trunk just to learn the same window
render_playlist itself renders — media_plane’s own module doc:
writer cost is O(N) in cursor count, so a cursor is per distinct
consumer, never per peer, and never duplicated for data another
cursor already tracks.
Trait Implementations§
Source§impl ServedEgress for HlsOrigin
impl ServedEgress for HlsOrigin
Source§type Request = HlsRequest
type Request = HlsRequest
Source§type Body = HlsBody
type Body = HlsBody
Source§fn resolve(
&self,
request: HlsRequest,
now: Timestamp,
await_policy: AwaitPolicy,
) -> EgressResponse<HlsBody>
fn resolve( &self, request: HlsRequest, now: Timestamp, await_policy: AwaitPolicy, ) -> EgressResponse<HlsBody>
request against this implementation’s current state at
time now, bounded by await_policy — see
EgressResponse::Await’s contract.