This seems to reduce flakiness in the TextDisplayer tests. The
theory is that Safari throttles timers when the system is very busy,
which it often is during full test runs across multiple browsers. By
not relying on timers and triggering an explicit update in the
TextDisplayer, the tests seem to become more reliable.
There was an exception to waitForEnd in StreamingEngine tests that
could have been handled generically inside the waiter for all tests.
It was also necessary to poll for ended state since the Firefox 99 update.
This fixes some recent test failures on Firefox 99.
Parse EXT-X-GAP HLS tag and add a status enum to shaka.media.SegmentReference.
shaka.media.SegmentReference.Status.AVAILABLE --> Normal behaviour
shaka.media.SegmentReference.Status. UNAVAILABLE --> Related to https://github.com/shaka-project/shaka-player/issues/2541
shaka.media.SegmentReference.Status. MISSING --> EXT-X-GAP in HLS
Note: only the parsing is added, but the functionality is not yet implemented.
Issue https://github.com/shaka-project/shaka-player/issues/1308
Below are the changelog entries for each deprecated feature removed by this commit.
-----
feat(config)!: `manifest.dash.defaultPresentationDelay` has been replaced by `manifest.defaultPresentationDelay` (deprecated in v3.0.0)
feat(config)!: Configuration of factories should be plain factory functions, not constructors; these will not be invoked with `new` (deprecated in v3.1.0)
feat(player)!: `shaka.Player.prototype.addTextTrack()` has been replaced by `addTextTrackAsync()`, which returns a `Promise` (deprecated in v3.1.0)
feat(ui)!: `shaka.ui.TrackLabelFormat` has been renamed to `shaka.ui.Overlay.TrackLabelFormat` (deprecated in v3.1.0)
feat(ui)!: `shaka.ui.FailReasonCode` has been renamed to `shaka.ui.Overlay.FailReasonCode` (deprecated in v3.1.0)
feat(offline)!: `shaka.offline.Storage.prototype.store()` returns `AbortableOperation` instead of `Promise` (deprecated in v3.0.0)
feat(offline)!: `shaka.offline.Storage.prototype.getStoreInProgress()` has been removed; concurrent operations are supported, so callers don't need to check this (deprecated in v3.0.0)
feat!: `shaka.util.Uint8ArrayUtils.equal` has been replaced by `shaka.util.BufferUtils.equal`, which can handle multiple types of buffers (deprecated in v3.0.0)
feat(manifest)!: `shaka.media.SegmentIndex.prototype.destroy()` has been replaced by `release()`, which is synchronous (deprecated in v3.0.0)
feat(manifest)!: `shaka.media.SegmentIterator.prototype.seek()`, which mutates the iterator, has been replaced by `shaka.media.SegmentIndex.getIteratorForTime()` (deprecated in v3.1.0)
feat(manifest)!: `shaka.media.SegmentIndex.prototype.merge()` has become private; use `mergeAndEvict()` instead (deprecated in v3.2.0)
feat(plugin)!: `AbrManager` plugins must implement the `playbackRateChanged()` method (deprecated in v3.0.0)
feat(plugin)!: `shaka.extern.Cue.prototype.spacer` has been replaced by the more clearly-named `lineBreak` (deprecated in v3.1.0)
feat(plugin)!: `IUIElement` plugins must have a `release()` method (not `destroy()`) (deprecated in v3.0.0)
This change fixes tests on Chromecast by loading tests later in the process. Test scripts are now dynamically inserted by boot.js, rather than loaded by Karma. The bootstrapping code then awaits the completion of that before starting the Karma frameworks (Jasmine) to run the tests.
This also removes the use of goog.provide/goog.require in tests and test utils. We don't need to load test utils or library sources dynamically in each test, and this gives us more explicit control over script loading and ordering.
Closes#4094
Jasmine 4 deprecated some part of its custom matcher API.
This puts us in compliance with the new API (by omitting a parameter
we didn't really need), and silences the deprecation warnings (which
only showed up when enabling logging in the tests).
This PR fixes#3242 where for some live streams using segmented VTT, text timings are relative to segment start instead of being absolute.
The PR introduces a new setting: `manifest.segmentRelativeVttTiming: boolean` allowing such alternative timing offset calculation.
The setting is off by default, preserving the current player behaviour.
Co-authored-by: Joey Parrish <joeyparrish@users.noreply.github.com>
Example content protection tags parsed:
```xml
<ContentProtection schemeIdUri="urn:mpeg:dash:mp4protection:2011" value="cenc" cenc:default_KID="<default key id>" />
<ContentProtection value="ClearKey1.0" schemeIdUri="urn:uuid:e2719d58-a985-b3c9-781a-b030af78d30e">
<clearkey:Laurl Lic_type="EME-1.0">License Url</clearkey:Laurl>
```
The player parses the default key id and license url,
and sends a POST request to license url as per https://w3c.github.io/encrypted-media/#clear-key-request-format to retrieve the decryption key/s.
For content where the manifest parser uses the notifySegments API
(DASH SegmentBase/SegmentList/SegmentTimeline, or HLS, but not DASH
SegmentTemplate+duration), the Player seekRangeEnd configuration was
not being honored correctly.
This fixes the issue in PresentationTimeline and adds a regression
test to our playRangeStart/playRangeEnds tests.
Fixed#4026
This makes the HLS parser read the EXT-X-PROGRAM-DATE-TIME value
on manifests, and use it to make sure that segments are inserted at
the correct place in the timeline, when in sequence mode.
Issue #2337
We filter out text streams that are duplicates, before persenting
them to the end user. A duplicate is detected by checking if
various values on the streams are the same.
However, we were not checking for bandwidth. This could lead to a
text stream being marked as a duplicate if it had the same language,
label, etc as another, even if they did not contain the same text.
This changes the utility to also check bandwidth.
Closes#3724
HLS now appends segments in sequence mode. In order to handle seeks,
we set the timestampOffset property on SourceBuffer to the startTime of
the segment. This is done after every seek, or on startup.
For non-sequence-mode content (DASH), we normally set timestampOffset
based on the Period structure. This should be suppressed in sequence
mode, though, where only the reference startTime matters.
The buffering issue was caused by two things in combination:
1. The HLS parser set meaningless timestampOffset values that would
change when a playlist was updated
2. We would use those timestampOffset values in setStreamProperties,
even though this should be skipped in sequence mode
These two things in combination would lead MediaSourceEngine to start
inserting segments near the start of the presentation, rather than at
the live edge.
This changes MediaSourceEngine so that in sequence mode, timestampOffset
is ignored in setStreamProperties. This also cleans up the HLS parser
to set each reference's timestampOffset to 0, since they should be
ignored anyway.
This updates the compiler and closure library to the latest releases.
This required a few small tweaks:
- Drop custom extern for WebCrypto (now built into the compiler)
- Remove require() in cea parser, only used in `throws` annotations
- Hack around a typing issue in a fake version of TextTrack in tests
If a manifest lists 2 audio streams, select the first acceptable stream instead of the last one. For example below, previously the 2nd stream was selected, and now the first stream will be selected. Other players like roku, video.js and exoplayer select the first one.
```
#EXT-X-MEDIA:TYPE=AUDIO,URI="stream_1.m3u8",GROUP-ID="default-audio-group",NAME="128k",AUTOSELECT=YES,CHANNELS="2"
#EXT-X-MEDIA:TYPE=AUDIO,URI="stream_2.m3u8",GROUP-ID="default-audio-group",NAME="64k",CHANNELS="2"
(video streams snipped)
```
EventStreams in DASH generate TimelineRegionInfo objects, which are
then stored in the RegionTimeline and RegionObserver classes. But
DashParser would add all regions to RegionTimeline, even if they would
be quickly removed again, and RegionObserver would cache some regions
from the timeline without ever removing them.
This fixes the issue from both of those directions. DashParser will
now ignore regions that are outside the DVR window (and therefore
would soon be removed from RegionTimeline), and RegionObserver listens
to an event on RegionTimeline to clean up its own storage when regions
fall outside the DVR window during playback.
Closes#3949 (memory leak in DASH live streams with inband EventStream)
When running in sequence mode, we ignore the normal timestamps
of video and audio segments. This lead to problems in some Apple-
encoded webvtt content, which used the X-TIMESTAMP-MAP tag to account
for the timestamp offsets in their video. Thus, those subtitles would
end up 10 seconds offset.
This changes the webvtt parser to ignore the X-TIMESTAMP-MAP when in
sequence mode.
Issue #2337
Three classes (RegionTimeline, RegionObserver, and QualityObserver)
were all designed with callbacks instead of events. A single callback
is inflexible compared to events, which allow multiple listeners. We
already have a long-standing and robust event system, so why not use
it?
Issue #3949 (memory leak in DASH live streams with inband EventStream)
Instead of waiting for the playhead to reach a specific time that we
know to be the end, then expecting ended to be true, we can use the
purpose-built waiter that waits for the ended event.
We also need to set the timeout explicitly, so that we have enough
time to play through to the end.
This adds code to allow Shaka Player to play media in sequence
mode, an alternate playback mode that makes the browser ignore
media timestamps, when playing HLS media.
This is important for containerless media formats, as they do not
contain such timestamps.
Changing HLS to not require timestamps also means that we no
longer need to fetch media segments in order to get the start
time, which should lower bandwidth usage and startup delay.
In initial tests, on a simulated 3G network, load latency went down
from an average 3.16s to 2.61s on the HLS version of "Big Buck Bunny:
the Dark Truths of a Video Dev Cartoon"; an improvement of about 17%.
Issue #2337
Change-Id: I507898d74ae30ddfb1bddf8dce643780949fbd9b
Add support for HLS com.apple.streamingkeydelivery through MSE/EME implementation.
Close#3346
## Tests
Tested on:
- Mac 11.6 Safari 15.2
- iOS 15.2 Safari 15.2
- Mac 11.6 Chrome 96 (for potential regressions on Widevine keySystem)
| Mode | DRM API | TS | CMAF (mono-key and multi-keys)
|---|---|---|---|
| file | EME | ✅ | ✅ |
| file | Legacy-prefixed | ✅ | ✅ |
| media-source | EME | **mux-js**: `encrypted` never fired<br />**real MSE**: `encrypted` event received, but with incorrect `sinf` initData (*1) | ✅ |
| media-source | Legacy-prefixed | **mux-js**: `webkitneedkey` never fired<br/>**real MSE**: TBD | 🔴 fails to append media segment to SourceBuffer (init segment ok) `(video:4) – "failed fetch and append: code=3015"` |
## Support table
| Mode | DRM API | TS | CMAF (mono-key and multi-keys)
|---|---|---|---|
| file | EME | ✅ | ✅ |
| file | Legacy-prefixed | ✅ | ✅ |
| media-source | EME | 🚫 `4040: HLS_MSE_ENCRYPTED_MP2T_NOT_SUPPORTED` | ✅ |
| media-source | Legacy-prefixed | 🚫 `4041: HLS_MSE_ENCRYPTED_LEGACY_APPLE_MEDIA_KEYS_NOT_SUPPORTED` |🚫 `4041: HLS_MSE_ENCRYPTED_LEGACY_APPLE_MEDIA_KEYS_NOT_SUPPORTED` |
⚠️ Use EME APIs with multi-keys CMAF makes the video stalling with the audio continuing alone after a short time (~3 minutes in the stream, could be shorter, could be longer). Didn't find an explanation to that yet. I've observed the same behaviour with hls.js code so I don't think this is a player issue.
* test: Switch local Chrome, Edge, Firefox, and Safari launchers to WebDriver-based
This will enable WebDriver-based screenshot tests in local test runs.
* test: Add screenshots for Edge on Mac
The screenshot review page now has options to organize screenshots either by test or by platform. Previously, it was only by test. This is useful if you want to review many anomalous screenshots for a particular device.
Instead of pixel-wise comparison with a change threshold, we now use a
structural similarity (ssim) module to decide how much a screenshot
has changed. This better tolerates small rendering differences due to
differences in GPUs across machines.
The recent changes to TTML parsing, to not inherit regions,
inadvertently ended up breaking text alignment in situations
where a region with alignment was on the p or div above a span.
Previously, we only inherited the text and display alignment
from a region on leaf nodes... which was a problem, since we
also didn't apply any styles to text nodes.
Change-Id: I62ac155bc4310a5f7da52c10ca2dd434f8015c97
This changes the TTML parser to not allow cue regions to be inherited
to the children of the element the region was originally assigned on,
except for the purposes of styles (colors, etc).
To allow regions on elements "above" the cues in TTML, such as the
<body> or <div> elements, this also changes the TTML parser to render
the full structure of the TTML file as a tree of cues. The end result
will be a single cue representing the <body>, with children
representing the <div> elements inside it, and those <divs> will have
children that represent the actual cues. Now that our text displayer
can intelligently update child cues as they enter or leave the display
window, this approach should be possible.
Closes#3850Closes#3741
Change-Id: Ia8d750daa06920610c04e9b26e29d2d304eaf8a9
Previously, we only cleared the buffer if the media state had
something buffered. This ensured that we did not pointlessly clear the
buffer when nothing was there.
However, this lead to problems if a seek was performed early during the
loading process, before the source buffer is initialized. During that
time, nothing is buffered, so we would not clear the buffer on a seek.
This lead to us accidentally fetching content from the beginning of the
presentation, rather than starting from the new clock time.
This changes the streaming engine to also clear the buffer if
mediaState.performingUpdate is true, to avoid that situation.
Closes#3299