Constructor
new MSFParser()
Members
EVENT_TIMELINE_PACKAGING_ :string
The catalog `packaging` value of an event timeline track.
Type:
- string
- Source:
INDEX_RETENTION_SEC_ :number
How many seconds of SegmentReferences to keep in the index behind the newest
one.
Must exceed how far StreamingEngine can lag the live edge, because it walks
the index in order and cannot skip to content whose predecessor has been
evicted. Where one reference is one frame this is a large number of
references but a small amount of memory.
Type:
- number
- Source:
LIVE_EDGE_TOLERANCE_SEC_ :number
How close to the live edge a seek target has to land to be treated as a
return to the live edge rather than as a seek into the DVR window, in
seconds.
Seeking to "live" lands on the seek range end, which is the newest segment
end time; by the time the seek is handled the edge may have moved on, so an
exact comparison would read the seek as one into the past and anchor the
subscription just behind the edge instead of following it.
Type:
- number
- Source:
MEDIA_TIMELINE_PACKAGING_ :string
The catalog `packaging` value of a media timeline track.
Type:
- string
- Source:
MIN_AVAILABILITY_WINDOW_SEC_ :number
Floor for the live segment-availability window, in seconds.
Deriving the window from one object's duration gives tens of milliseconds on
a frame-per-object packaging. That is too narrow on two counts: the
playhead, which trails the live edge, falls outside its own seek range and
is re-seeked continuously; and the trailing track of a pair published a few
hundred milliseconds apart is never inside the window at all, so
StreamingEngine reports "cannot find segment" for it forever.
Bounded from above as well. This window IS the seek range, so it is what
the player offers the user as DVR, and it is how far the playhead may drift
behind the live edge before being pulled back to it. Neither is wanted on a
transport chosen for low latency, and a window of five seconds or more also
makes the UI show a seek bar (shaka.ui.SeekBar's minimum seek window), which
would advertise DVR on a stream that has none.
The quantity it has to cover is the lag between the newest reference and the
newest sample actually appended, since that is where the playhead can be.
Measured on a live LOC stream, that lag ran 2.0-4.7 s and the playhead sat
1.0-3.8 s behind the live edge; a window of 1.5 s put it outside the range
again and it thrashed.
Type:
- number
- Source:
activeStreams_ :Map<string, shaka.msf.MSFParser.StreamState>
The streams that are currently subscribed, by track key. A seek has to
find them to re-point their subscriptions, which is why the state that
used to live in createSegmentIndex's closure is out here.
Type:
- Map<string, shaka.msf.MSFParser.StreamState>
- Source:
bandwidthSamples_ :Map<string, {bytes: number, readMs: number, group: bigint}>
The in-progress ABR bandwidth sample for each track, keyed by track key.
Tracks are accumulated separately because each has its own group
sequence.
Type:
- Map<string, {bytes: number, readMs: number, group: bigint}>
- Source:
catalogPromise_ :Promise.PromiseWithResolvers
Type:
- Promise.PromiseWithResolvers
- Source:
catalogReceived_ :boolean
Whether the catalog the presentation is built from has been received.
Only the first complete catalog is used; what the catalog track says
after it is not applied yet.
Type:
- boolean
- Source:
eventTimelines_ :Array<!shaka.msf.EventTimeline>
The event timelines of the event timeline tracks subscribed to.
Type:
- Array<!shaka.msf.EventTimeline>
- Source:
mediaTimelineDepends_ :Map<string, !Array<string>>
The tracks each media timeline track describes, by the timeline track's
name. An event timeline names the timeline track in its `depends`, while
the timelines themselves are kept by the media track they describe, so
this is what gets from one to the other.
Type:
- Map<string, !Array<string>>
- Source:
mediaTimelines_ :Map<string, !shaka.msf.MediaTimeline>
The media timeline of each track that has one, by catalog track name.
A track gets one from a media timeline track that names it in `depends`,
from its own `template` field, or from both, in which case the one
instance holds both and prefers the explicit records.
Type:
- Map<string, !shaka.msf.MediaTimeline>
- Source:
pendingSubscriptions_ :Map<string, {cancelled: boolean}>
Subscriptions whose SUBSCRIBE_OK has not arrived yet, by track key.
A subscription can only be withdrawn once it has an alias, so a track
closed before then has to leave a note for the in-flight subscribe to
find; without it the subscription is orphaned and the publisher keeps
sending objects nobody listens to for the rest of the session.
Type:
- Map<string, {cancelled: boolean}>
- Source:
publishNamespaces_ :Array<Array<string>>
Type:
- Array<Array<string>>
- Source:
receivedFirstSegment_ :Set<shaka.util.ManifestParserUtils.ContentType>
Tracks whether the first segment has been received for each content type.
Used to delay locking the presentation timeline until all expected
stream types have started producing data.
Type:
- Source:
unregisterPublishNamespaceCallback_ :?function()
Type:
- ?function()
- Source:
unregisterTracksCallback_ :Map<string, function()>
Type:
- Map<string, function()>
- Source:
Methods
isIndexed_(segmentIndexnon-null, time) → {boolean}
Whether a segment index holds a reference covering the given time.
SegmentIndex.find() answers a position, and for a time before everything it
holds it answers the first position rather than nothing, so its result says
where to look, not whether the time is there. Seeking behind the index is
exactly the case that distinction decides.
Parameters:
| Name | Type | Description |
|---|---|---|
segmentIndex |
shaka.media.SegmentIndex | |
time |
number |
- Source:
Returns:
- Type
- boolean
namespaceTuple(namespace, sessionNamespace) → {Array<string>}
Converts a catalog track's `namespace` string into the Track Namespace
tuple that goes on the wire.
A Track Namespace is an ordered set of fields (MoQT Section 2.4.1), but the
catalog carries it as one string whose fields are joined with "/", as in
the MSF example "conference.example.com/conference123/alice". Sending that
string as a single field never matches a namespace announced as several.
When the string is the session's own namespace written out, the session's
tuple is used as is, so a publisher whose single field contains a "/" keeps
working. Otherwise the string is split on "/", dropping empty fields
because a field must carry at least one byte.
Parameters:
| Name | Type | Description |
|---|---|---|
namespace |
string | |
sessionNamespace |
Array<string> |
- Source:
Returns:
- Type
- Array<string>
addSegment_(stream, type, segmentnon-null, initSegmentReference)
Adds a segment produced by a packaging's segmenter to a stream's segment
index and advances the presentation timeline to cover it.
Parameters:
| Name | Type | Description |
|---|---|---|
stream |
shaka.extern.Stream | |
type |
shaka.util.ManifestParserUtils.ContentType | |
segment |
shaka.extern.MsfSegment | |
initSegmentReference |
shaka.media.InitSegmentReference |
- Source:
banLocation(uri)
Tells the parser that a location should be banned. This is called on
retry.
Parameters:
| Name | Type | Description |
|---|---|---|
uri |
string |
- Implements:
- Source:
configure(config, isPreloadFnopt)
Called by the Player to provide an updated configuration any time the
configuration changes. Will be called at least once before start().
Parameters:
| Name | Type | Attributes | Description |
|---|---|---|---|
config |
shaka.extern.ManifestConfiguration | ||
isPreloadFn |
function |
<optional> |
- Implements:
- Source:
createCatalogCallback_(storenon-null) → {shaka.msf.Utils.ObjectCallback}
Builds the callback for the catalog track's Objects, which rebuilds the
catalog from them and resolves the catalog promise with the first
complete one.
Parameters:
| Name | Type | Description |
|---|---|---|
store |
shaka.msf.CatalogStore |
- Source:
Returns:
createDecodingCallback_(handler, onError) → {shaka.msf.Utils.ObjectCallback}
Wraps a handler for the Objects of a JSON track -- the catalog or a media
timeline -- so that each payload reaches it with its MSF_COMPRESSION
undone, and in the order the Objects arrived. Order matters: the first
Object of a Group is a complete document and the ones after it are
updates to it, and a compressed complete document takes longer to decode
than the uncompressed update that follows it.
An uncompressed payload with nothing waiting ahead of it is handled in the
same turn it arrives.
Objects with no payload carry an Object status (e.g. an end-of-group
marker), not a document, and are skipped.
Parameters:
| Name | Type | Description |
|---|---|---|
handler |
function(!shaka.msf.Utils.MOQObject, !Uint8Array) | |
onError |
function(*) | Receives the reason a payload could not be decoded, which is a shaka.util.Error when its compression is not supported. The Object is dropped. |
- Source:
Returns:
createVariants_()
- Source:
decodePayload_(objnon-null) → {Uint8Array|!Promise<!Uint8Array>}
An Object's payload with its MSF_COMPRESSION undone.
Parameters:
| Name | Type | Description |
|---|---|---|
obj |
shaka.msf.Utils.MOQObject |
- Source:
Returns:
- Type
- Uint8Array | !Promise<!Uint8Array>
getContentProtections_(catalog) → {Map<string, !shaka.extern.DrmInfo>}
Parameters:
| Name | Type | Description |
|---|---|---|
catalog |
msfCatalog.Catalog |
- Source:
Returns:
- Type
- Map<string, !shaka.extern.DrmInfo>
getEventRecordHandler_(eventType) → {?function(shaka.msf.EventTimeline.Record, number)}
What consumes the records of an event timeline of the given type, or null
when nothing here does. What a record's `data` means is defined by the
type, so this is the one place that knows about any of them.
Parameters:
| Name | Type | Description |
|---|---|---|
eventType |
string |
- Source:
Returns:
- Type
- ?function(shaka.msf.EventTimeline.Record, number)
getEventRecordTime_(record, dependsnon-null) → {number}
Where an event timeline record falls on the presentation timeline, in
seconds, or null when it cannot be placed yet.
A media time is a presentation time already (MSF 7.1.1). A Location or a
wallclock time has to go through the media timeline of a track the
record's track depends on.
Parameters:
| Name | Type | Description |
|---|---|---|
record |
shaka.msf.EventTimeline.Record | |
depends |
Array<string> | The event timeline track's `depends`. |
- Source:
Returns:
- Type
- number
getMediaTimelinesFor_(dependsnon-null) → {Array<!shaka.msf.MediaTimeline>}
The media timelines a track that depends on the given tracks can use.
`depends` names either media timeline tracks, as in the MSF catalog
examples, whose timelines are kept by the media tracks they in turn
depend on, or media tracks that carry a template. MSF only requires
`depends` of an event timeline whose records refer to a media timeline,
so an empty one falls back to every timeline the presentation has, in
catalog order.
Parameters:
| Name | Type | Description |
|---|---|---|
depends |
Array<string> |
- Source:
Returns:
- Type
- Array<!shaka.msf.MediaTimeline>
getOrCreateTimeline_(trackName) → {shaka.msf.MediaTimeline}
Parameters:
| Name | Type | Description |
|---|---|---|
trackName |
string |
- Source:
Returns:
getTimelineWindowStart_() → {number}
The earliest presentation time the player can seek to and actually be
served, or null when there is no such point and the window should stay at
the live edge.
Every subscribed track has to be able to reach it, so this is the latest
of their starts and is null as soon as one of them has no timeline: a seek
range is a promise that all of the media is there, and half of it is a
stall rather than a seek.
- Source:
Returns:
- Type
- number
isPreloadFn_()
- Source:
listenForAnnouncements_()
Listen for announcements from the server
- Source:
onExpirationUpdated(sessionId, expiration)
Tells the parser that the expiration time of an EME session has changed.
Implementing this is optional.
Parameters:
| Name | Type | Description |
|---|---|---|
sessionId |
string | |
expiration |
number |
- Implements:
- Source:
onInitialVariantChosen(variant)
Tells the parser that the initial variant has been chosen.
Parameters:
| Name | Type | Description |
|---|---|---|
variant |
shaka.extern.Variant |
- Implements:
- Source:
onScte35Record_(eventType, record, time)
Reports a record of an SCTE-35 event timeline to the player
(draft-wilaw-moq-scte35-event-timeline).
Parameters:
| Name | Type | Description |
|---|---|---|
eventType |
string | |
record |
shaka.msf.EventTimeline.Record | |
time |
number |
- Source:
onSeeking_()
Re-points the subscriptions after a seek to content that has been
published but not received.
A MoQT subscription is a position in a track, not a URL to fetch, so this
is what a seek costs here: the subscription is withdrawn and asked for
again from the Location the media timeline gives for the target, and the
segment index starts over from there. Seeking within what has already
arrived costs nothing and is left alone.
- Source:
processCatalog_(catalog) → {Promise}
Parameters:
| Name | Type | Description |
|---|---|---|
catalog |
msfCatalog.Catalog |
- Source:
Returns:
- Type
- Promise
processEventTimelineTrack_(track)
Subscribes to an event timeline track whose `eventType` this player
consumes, and hands each of its records to the consumer once it can be
placed on the presentation timeline.
Parameters:
| Name | Type | Description |
|---|---|---|
track |
msfCatalog.Track |
- Source:
processMediaTimelineTrack_(track)
Subscribes to a media timeline track and feeds what it publishes to the
timelines of the tracks it describes.
Parameters:
| Name | Type | Description |
|---|---|---|
track |
msfCatalog.Track |
- Source:
processTrack_(track, contentProtectionsnon-null, initDataListnon-null)
Parameters:
| Name | Type | Description |
|---|---|---|
track |
msfCatalog.Track | |
contentProtections |
Map<string, !shaka.extern.DrmInfo> | |
initDataList |
Map<string, string> |
- Source:
recordBandwidthSample_(trackKey, location, byteLength, readMs)
Feed the ABR bandwidth estimator.
MoQ delivers media as many small per-object (often per-frame) chunks, which
are individually too small for the bandwidth estimator to draw a useful
throughput sample from. A group is the natural aggregation unit, so
accumulate a group's objects and report one sample once the group is
complete, which we detect by the object's group changing.
The time reported is the sum of the per-object active read
durations, not wall clock. A push stream delivers at (roughly) the encoded
rate, so wall-clock timing would only ever measure the current variant's
bitrate and ABR could never learn there is spare capacity. When the link
has headroom the objects sit ready in the transport buffer and read almost
instantly, so the active read time reflects the true link speed and lets
ABR climb to a variant the connection can actually sustain.
Parameters:
| Name | Type | Description |
|---|---|---|
trackKey |
string | |
location |
shaka.msf.Utils.Location | |
byteLength |
number | |
readMs |
number | Active time spent reading this object from the stream. |
- Source:
resubscribe_(state, startLocationnullable)
Starts a subscription that nothing waits on, reporting its failure to the
player instead of leaving it to reject unheard.
Parameters:
| Name | Type | Attributes | Description |
|---|---|---|---|
state |
shaka.msf.MSFParser.StreamState | ||
startLocation |
shaka.msf.Utils.Location |
<nullable> |
- Source:
setMediaElement(mediaElement)
Set media element.
Parameters:
| Name | Type | Description |
|---|---|---|
mediaElement |
HTMLMediaElement |
- Implements:
- Source:
start(uri, playerInterface) → {Promise<shaka.extern.Manifest>}
Initialize and start the parser. When |start| resolves, it should return
the initial version of the manifest. |start| will only be called once. If
|stop| is called while |start| is pending, |start| should reject.
Parameters:
| Name | Type | Description |
|---|---|---|
uri |
string | The URI of the manifest. |
playerInterface |
shaka.extern.ManifestParser.PlayerInterface | The player interface contains the callbacks and members that the parser can use to communicate with the player and outside world. |
- Implements:
- Source:
Returns:
- Type
- Promise<shaka.extern.Manifest>
startSubscription_(state, startLocationnullable) → {Promise}
Subscribes a stream's track and turns the Objects it delivers into
segments, from the live edge or from a given Location.
Parameters:
| Name | Type | Attributes | Description |
|---|---|---|---|
state |
shaka.msf.MSFParser.StreamState | ||
startLocation |
shaka.msf.Utils.Location |
<nullable> |
Where to start, or null for the live edge. |
- Source:
Returns:
Resolves once the subscription has produced its first
segment, and rejects with MSF_SUBSCRIBE_FAILED if the publisher refuses
to serve the track from the live edge.
- Type
- Promise
stop() → {Promise}
Tell the parser that it must stop and free all internal resources as soon
as possible. Only once all internal resources are stopped and freed will
the promise resolve. Once stopped a parser will not be started again.
The parser should support having |stop| called multiple times and the
promise should always resolve.
- Implements:
- Source:
Returns:
- Type
- Promise
stopSubscription_(state)
Withdraws a stream's subscription, leaving its segment index alone.
Parameters:
| Name | Type | Description |
|---|---|---|
state |
shaka.msf.MSFParser.StreamState |
- Source:
subscribeToCatalog_(namespace) → {Promise}
Subscribe to the catalog in the given namespace.
MSF requires a SUBSCRIBE that also retrieves the current Group from its
first Object: that Object is the latest complete catalog, and the
subscription alone would only deliver what is published after it, which
may be nothing at all.
Parameters:
| Name | Type | Description |
|---|---|---|
namespace |
Array<string> |
- Source:
Returns:
- Type
- Promise
subscribeToOptionalJsonTrack_(track, trackKey, description, handler)
Subscribes to a track of JSON documents the presentation can do without,
such as a media or event timeline, and hands each payload to the handler
with its MSF_COMPRESSION undone and in the order the Objects arrived.
An Object that fails to decompress is dropped. A compression we cannot
undo at all is a different matter: MSF forbids reading the track and says
to unsubscribe, and since the track is optional, playback carries on
without it.
Parameters:
| Name | Type | Description |
|---|---|---|
track |
msfCatalog.Track | |
trackKey |
string | |
description |
string | What the track is, for the log. |
handler |
function(!shaka.msf.Utils.MOQObject, !Uint8Array) |
- Source:
subscribeToTrack(track, trackKey, callback, startLocationopt, nullable) → {Promise<?Error>}
Parameters:
| Name | Type | Attributes | Description |
|---|---|---|---|
track |
msfCatalog.Track | ||
trackKey |
string | ||
callback |
shaka.msf.Utils.ObjectCallback | ||
startLocation |
shaka.msf.Utils.Location |
<optional> <nullable> |
Where delivery should begin, or null to start at the live edge. A start at the live edge joins the current Group from its first Object, which is where media can start decoding and where a timeline track restates itself in full, rather than starting mid-group or waiting for the next Group. |
- Source:
Returns:
Why the publisher refused the subscription,
or null when it did not: either the track is subscribed, or it was
closed before the answer came and nothing is wanted any more. A
publisher can refuse a request, and one that starts at a Location is
the likeliest to be refused: the Group asked for may be older than
anything the publisher still holds, whatever its media timeline said.
- Type
- Promise<?Error>
update()
Tells the parser to do a manual manifest update. Implementing this is
optional. This is only called when 'emsg' boxes are present.
- Implements:
- Source:
updateAvailabilityWindow_()
Sizes the segment availability window, which is what the player offers as
the seek range.
Without a media timeline the window is a floor around the live edge and
the presentation has no DVR, because nothing says where to subscribe from
to get anything older. With one, the window reaches back to the oldest
point the timeline still describes.
- Source:
Type Definitions
StreamState
What the parser keeps for a stream that is currently subscribed. It is
everything a subscription needs to be started again from somewhere else,
which is what a seek does.
Type:
- {stream: shaka.extern.Stream, type: shaka.util.ManifestParserUtils.ContentType, track: msfCatalog.Track, trackKey: string, packaging: shaka.extern.MsfPackaging, description: shaka.extern.MsfTrackDescription, startLocation: ?shaka.msf.Utils.Location, generation: number}
Properties:
| Name | Type | Attributes | Description |
|---|---|---|---|
stream |
shaka.extern.Stream | The stream this track feeds. | |
type |
shaka.util.ManifestParserUtils.ContentType | The stream's content type. | |
track |
msfCatalog.Track | The catalog track, which is what a subscription is addressed with. | |
trackKey |
string | The namespace-qualified track name, used as the subscription key. | |
packaging |
shaka.extern.MsfPackaging | The packaging that makes segments out of this track's Objects. | |
description |
shaka.extern.MsfTrackDescription | What the packaging derived from the catalog, held for the initialization segment reference every segment carries. | |
startLocation |
shaka.msf.Utils.Location |
<nullable> |
Where the current subscription was asked to start, or null when it follows the live edge. |
generation |
number | Counts the subscriptions this stream has had, so that Objects still in flight from a previous one can be told apart and dropped. |
- Source: