feat!: Remove all deprecated things (#9162)

This commit is contained in:
Álvaro Velad Galván
2025-10-07 10:52:13 +02:00
committed by GitHub
parent 9df740a006
commit 945c57ab77
46 changed files with 234 additions and 2975 deletions
-2
View File
@@ -71,7 +71,6 @@
+../../lib/text/cue.js
+../../lib/text/cue_region.js
+../../lib/text/native_text_displayer.js
+../../lib/text/simple_text_displayer.js
+../../lib/text/speech_to_text.js
+../../lib/text/stub_text_displayer.js
+../../lib/text/text_engine.js
@@ -95,7 +94,6 @@
+../../lib/util/error.js
+../../lib/util/event_manager.js
+../../lib/util/exp_golomb.js
+../../lib/util/fairplay_utils.js
+../../lib/util/fake_event.js
+../../lib/util/fake_event_target.js
+../../lib/util/functional.js
+2 -3
View File
@@ -75,9 +75,8 @@ destroyed.
#### registration
At the end of the file, you should register the parser with the library. This
will allow it to be used by the `Player`. There are two methods:
`registerParserByExtension` and `registerParserByMime`. They both add parsers
to a registry of manifest parsers. When the Player gets a URI, it will
will allow it to be used by the `Player`. Use `registerParserByMime` to add the
parser to the registry of manifest parsers. When the Player gets a URI, it will
determine which parser to use. It will first try based on the file extension,
then it will make a HEAD request to the URI to get back a MIME type.
-5
View File
@@ -317,11 +317,6 @@ shaka.extern.IAdManager = class extends EventTarget {
*/
replaceServerSideAdTagParameters(adTagParameters) {}
/**
* @return {!Array<!shaka.extern.AdCuePoint>}
*/
getServerSideCuePoints() {}
/**
* @return {!Array<!shaka.extern.AdCuePoint>}
*/
-16
View File
@@ -921,7 +921,6 @@ shaka.extern.HLSInterstitial;
* endTime: number,
* id: string,
* timescale: number,
* eventElement: Element,
* eventNode: ?shaka.extern.xml.Node
* }}
*
@@ -942,9 +941,6 @@ shaka.extern.HLSInterstitial;
* Specifies an identifier for this instance of the region.
* @property {number} timescale
* Provides the timescale, in ticks per second.
* @property {Element} eventElement
* <b>DEPRECATED</b>: Use eventNode instead.
* The XML element that defines the Event.
* @property {?shaka.extern.xml.Node} eventNode
* The XML element that defines the Event.
* @exportDoc
@@ -1399,7 +1395,6 @@ shaka.extern.xml.Node;
* ignoreEmptyAdaptationSet: boolean,
* ignoreMaxSegmentDuration: boolean,
* keySystemsByURI: !Object<string, string>,
* manifestPreprocessor: function(!Element),
* manifestPreprocessorTXml: function(!shaka.extern.xml.Node),
* sequenceMode: boolean,
* useStreamOnceInPeriodFlattening: boolean,
@@ -1459,11 +1454,6 @@ shaka.extern.xml.Node;
* @property {Object<string, string>} keySystemsByURI
* A map of scheme URI to key system name. Defaults to default key systems
* mapping handled by Shaka.
* @property {function(!Element)} manifestPreprocessor
* <b>DEPRECATED</b>: Use manifestPreprocessorTXml instead.
* Called immediately after the DASH manifest has been parsed into an
* XMLDocument. Provides a way for applications to perform efficient
* preprocessing of the manifest.
* @property {function(!shaka.extern.xml.Node)} manifestPreprocessorTXml
* Called immediately after the DASH manifest has been parsed into an
* XMLDocument. Provides a way for applications to perform efficient
@@ -1602,17 +1592,11 @@ shaka.extern.HlsManifestConfiguration;
/**
* @typedef {{
* manifestPreprocessor: function(!Element),
* manifestPreprocessorTXml: function(!shaka.extern.xml.Node),
* sequenceMode: boolean,
* keySystemsBySystemId: !Object<string, string>
* }}
*
* @property {function(!Element)} manifestPreprocessor
* <b>DEPRECATED</b>: Use manifestPreprocessorTXml instead.
* Called immediately after the MSS manifest has been parsed into an
* XMLDocument. Provides a way for applications to perform efficient
* preprocessing of the manifest.
* @property {function(!shaka.extern.xml.Node)} manifestPreprocessorTXml
* Called immediately after the MSS manifest has been parsed into an
* XMLDocument. Provides a way for applications to perform efficient
-418
View File
@@ -8,7 +8,6 @@
goog.provide('shaka.ads.AdManager');
goog.require('goog.asserts');
goog.require('shaka.Deprecate');
goog.require('shaka.Player');
goog.require('shaka.ads.AdsStats');
goog.require('shaka.ads.ClientSideAdManager');
@@ -736,19 +735,6 @@ shaka.ads.AdManager = class extends shaka.util.FakeEventTarget {
}
/**
* @return {!Array<!shaka.extern.AdCuePoint>}
* @override
* @export
*/
getServerSideCuePoints() {
shaka.Deprecate.deprecateFeature(5,
'AdManager.getServerSideCuePoints',
'Please use getCuePoints function.');
return this.getCuePoints();
}
/**
* @return {!Array<!shaka.extern.AdCuePoint>}
* @override
@@ -942,410 +928,6 @@ shaka.ads.AdManager = class extends shaka.util.FakeEventTarget {
}
};
/**
* The event name for when a sequence of ads has been loaded.
*
* Deprecated, please use {@link shaka.ads.Utils}
*
* @const {string}
* @export
* @deprecated
*/
shaka.ads.AdManager.ADS_LOADED = 'ads-loaded';
/**
* The event name for when an ad has started playing.
*
* Deprecated, please use {@link shaka.ads.Utils}
*
* @const {string}
* @export
* @deprecated
*/
shaka.ads.AdManager.AD_STARTED = 'ad-started';
/**
* The event name for when an ad playhead crosses first quartile.
*
* Deprecated, please use {@link shaka.ads.Utils}
*
* @const {string}
* @export
* @deprecated
*/
shaka.ads.AdManager.AD_FIRST_QUARTILE = 'ad-first-quartile';
/**
* The event name for when an ad playhead crosses midpoint.
*
* Deprecated, please use {@link shaka.ads.Utils}
*
* @const {string}
* @export
* @deprecated
*/
shaka.ads.AdManager.AD_MIDPOINT = 'ad-midpoint';
/**
* The event name for when an ad playhead crosses third quartile.
*
* Deprecated, please use {@link shaka.ads.Utils}
*
* @const {string}
* @export
* @deprecated
*/
shaka.ads.AdManager.AD_THIRD_QUARTILE = 'ad-third-quartile';
/**
* The event name for when an ad has completed playing.
*
* Deprecated, please use {@link shaka.ads.Utils}
*
* @const {string}
* @export
* @deprecated
*/
shaka.ads.AdManager.AD_COMPLETE = 'ad-complete';
/**
* The event name for when an ad has finished playing
* (played all the way through, was skipped, or was unable to proceed
* due to an error).
*
* Deprecated, please use {@link shaka.ads.Utils}
*
* @const {string}
* @export
* @deprecated
*/
shaka.ads.AdManager.AD_STOPPED = 'ad-stopped';
/**
* The event name for when an ad is skipped by the user.
*
* Deprecated, please use {@link shaka.ads.Utils}
*
* @const {string}
* @export
* @deprecated
*/
shaka.ads.AdManager.AD_SKIPPED = 'ad-skipped';
/**
* The event name for when the ad volume has changed.
*
* Deprecated, please use {@link shaka.ads.Utils}
*
* @const {string}
* @export
* @deprecated
*/
shaka.ads.AdManager.AD_VOLUME_CHANGED = 'ad-volume-changed';
/**
* The event name for when the ad was muted.
*
* Deprecated, please use {@link shaka.ads.Utils}
*
* @const {string}
* @export
* @deprecated
*/
shaka.ads.AdManager.AD_MUTED = 'ad-muted';
/**
* The event name for when the ad was paused.
*
* Deprecated, please use {@link shaka.ads.Utils}
*
* @const {string}
* @export
* @deprecated
*/
shaka.ads.AdManager.AD_PAUSED = 'ad-paused';
/**
* The event name for when the ad was resumed after a pause.
*
* Deprecated, please use {@link shaka.ads.Utils}
*
* @const {string}
* @export
* @deprecated
*/
shaka.ads.AdManager.AD_RESUMED = 'ad-resumed';
/**
* The event name for when the ad's skip status changes
* (usually it becomes skippable when it wasn't before).
*
* Deprecated, please use {@link shaka.ads.Utils}
*
* @const {string}
* @export
* @deprecated
*/
shaka.ads.AdManager.AD_SKIP_STATE_CHANGED = 'ad-skip-state-changed';
/**
* The event name for when the ad's cue points (start/end markers)
* have changed.
*
* Deprecated, please use {@link shaka.ads.Utils}
*
* @const {string}
* @export
* @deprecated
*/
shaka.ads.AdManager.CUEPOINTS_CHANGED = 'ad-cue-points-changed';
/**
* The event name for when the native IMA ad manager object has
* loaded and become available.
*
* Deprecated, please use {@link shaka.ads.Utils}
*
* @const {string}
* @export
* @deprecated
*/
shaka.ads.AdManager.IMA_AD_MANAGER_LOADED = 'ima-ad-manager-loaded';
/**
* The event name for when the native IMA stream manager object has
* loaded and become available.
*
* Deprecated, please use {@link shaka.ads.Utils}
*
* @const {string}
* @export
* @deprecated
*/
shaka.ads.AdManager.IMA_STREAM_MANAGER_LOADED = 'ima-stream-manager-loaded';
/**
* The event name for when the ad was clicked.
*
* Deprecated, please use {@link shaka.ads.Utils}
*
* @const {string}
* @export
* @deprecated
*/
shaka.ads.AdManager.AD_CLICKED = 'ad-clicked';
/**
* The event name for when there is an update to the current ad's progress.
*
* Deprecated, please use {@link shaka.ads.Utils}
*
* @const {string}
* @export
* @deprecated
*/
shaka.ads.AdManager.AD_PROGRESS = 'ad-progress';
/**
* The event name for when the ad is buffering.
*
* Deprecated, please use {@link shaka.ads.Utils}
*
* @const {string}
* @export
* @deprecated
*/
shaka.ads.AdManager.AD_BUFFERING = 'ad-buffering';
/**
* The event name for when the ad's URL was hit.
*
* Deprecated, please use {@link shaka.ads.Utils}
*
* @const {string}
* @export
* @deprecated
*/
shaka.ads.AdManager.AD_IMPRESSION = 'ad-impression';
/**
* The event name for when the ad's duration changed.
*
* Deprecated, please use {@link shaka.ads.Utils}
*
* @const {string}
* @export
* @deprecated
*/
shaka.ads.AdManager.AD_DURATION_CHANGED = 'ad-duration-changed';
/**
* The event name for when the ad was closed by the user.
*
* Deprecated, please use {@link shaka.ads.Utils}
*
* @const {string}
* @export
* @deprecated
*/
shaka.ads.AdManager.AD_CLOSED = 'ad-closed';
/**
* The event name for when the ad data becomes available.
*
* Deprecated, please use {@link shaka.ads.Utils}
*
* @const {string}
* @export
* @deprecated
*/
shaka.ads.AdManager.AD_LOADED = 'ad-loaded';
/**
* The event name for when all the ads were completed.
*
* Deprecated, please use {@link shaka.ads.Utils}
*
* @const {string}
* @export
* @deprecated
*/
shaka.ads.AdManager.ALL_ADS_COMPLETED = 'all-ads-completed';
/**
* The event name for when the ad changes from or to linear.
*
* Deprecated, please use {@link shaka.ads.Utils}
*
* @const {string}
* @export
* @deprecated
*/
shaka.ads.AdManager.AD_LINEAR_CHANGED = 'ad-linear-changed';
/**
* The event name for when the ad's metadata becomes available.
*
* Deprecated, please use {@link shaka.ads.Utils}
*
* @const {string}
* @export
* @deprecated
*/
shaka.ads.AdManager.AD_METADATA = 'ad-metadata';
/**
* The event name for when the ad display encountered a recoverable
* error.
*
* Deprecated, please use {@link shaka.ads.Utils}
*
* @const {string}
* @export
* @deprecated
*/
shaka.ads.AdManager.AD_RECOVERABLE_ERROR = 'ad-recoverable-error';
/**
* The event name for when the ad manager dispatch errors.
*
* Deprecated, please use {@link shaka.ads.Utils}
*
* @const {string}
* @export
* @deprecated
*/
shaka.ads.AdManager.AD_ERROR = 'ad-error';
/**
* The event name for when the client side SDK signalled its readiness
* to play a VPAID ad or an ad rule.
*
* Deprecated, please use {@link shaka.ads.Utils}
*
* @const {string}
* @export
* @deprecated
*/
shaka.ads.AdManager.AD_BREAK_READY = 'ad-break-ready';
/**
* The event name for when the interaction callback for the ad was
* triggered.
*
* Deprecated, please use {@link shaka.ads.Utils}
*
* @const {string}
* @export
* @deprecated
*/
shaka.ads.AdManager.AD_INTERACTION = 'ad-interaction';
/**
* The name of the event for when an ad requires the main content to be paused.
* Fired when the platform does not support multiple media elements.
*
* Deprecated, please use {@link shaka.ads.Utils}
*
* @const {string}
* @export
* @deprecated
*/
shaka.ads.AdManager.AD_CONTENT_PAUSE_REQUESTED = 'ad-content-pause-requested';
/**
* The name of the event for when an ad requires the main content to be resumed.
* Fired when the platform does not support multiple media elements.
*
* Deprecated, please use {@link shaka.ads.Utils}
*
* @const {string}
* @export
* @deprecated
*/
shaka.ads.AdManager.AD_CONTENT_RESUME_REQUESTED = 'ad-content-resume-requested';
/**
* The name of the event for when an ad requires the video of the main content
* to be attached.
*
* Deprecated, please use {@link shaka.ads.Utils}
*
* @const {string}
* @export
* @deprecated
*/
shaka.ads.AdManager.AD_CONTENT_ATTACH_REQUESTED = 'ad-content-attach-requested';
/**
* Set this is a default ad manager for the player.
+10 -34
View File
@@ -11,6 +11,7 @@ goog.require('shaka.Player');
goog.require('shaka.cast.CastSender');
goog.require('shaka.cast.CastUtils');
goog.require('shaka.log');
goog.require('shaka.util.ArrayUtils');
goog.require('shaka.util.Error');
goog.require('shaka.util.EventManager');
goog.require('shaka.util.FakeEvent');
@@ -463,7 +464,6 @@ shaka.cast.CastProxy = class extends shaka.util.FakeEventTarget {
const initState = {
'video': {},
'player': {},
'playerAfterLoad': {},
'manifest': this.localPlayer_.getAssetUri(),
'startTime': null,
'addThumbnailsTrackCalls': this.addThumbnailsTrackCalls_,
@@ -492,14 +492,6 @@ shaka.cast.CastProxy = class extends shaka.util.FakeEventTarget {
initState['player'][setter] = value;
}
for (const pair of shaka.cast.CastUtils.PlayerInitAfterLoadState) {
const getter = pair[0];
const setter = pair[1];
const value = /** @type {Object} */(this.localPlayer_)[getter]();
initState['playerAfterLoad'][setter] = value;
}
return initState;
}
@@ -564,9 +556,6 @@ shaka.cast.CastProxy = class extends shaka.util.FakeEventTarget {
activeTextTrack = textTracks.find((t) => t.active);
}
const isTextTrackVisible =
this.sender_.get('player', 'isTextTrackVisible')();
// Now load the manifest, if present.
if (assetUri) {
// Don't autoplay the content until we finish setting up initial state.
@@ -601,19 +590,16 @@ shaka.cast.CastProxy = class extends shaka.util.FakeEventTarget {
this.localVideo_[name] = videoState[name];
}
for (const pair of shaka.cast.CastUtils.PlayerInitAfterLoadState) {
const getter = pair[0];
const setter = pair[1];
const value = this.sender_.get('player', getter)();
/** @type {Object} */(this.localPlayer_)[setter](value);
}
this.localPlayer_.setTextTrackVisibility(isTextTrackVisible);
if (activeTextTrack) {
this.localPlayer_.selectTextLanguage(
activeTextTrack.language,
activeTextTrack.roles,
activeTextTrack.forced);
const newTextTracks = this.localPlayer_.getTextTracks();
const trackToSelect = newTextTracks.find((t) => {
return t.language == activeTextTrack.language &&
shaka.util.ArrayUtils.equal(t.roles, activeTextTrack.roles) &&
t.forced == activeTextTrack.forced;
});
this.localPlayer_.selectTextTrack(trackToSelect);
} else {
this.localPlayer_.selectTextTrack();
}
// Restore the original autoplay setting.
@@ -819,16 +805,6 @@ shaka.cast.CastProxy = class extends shaka.util.FakeEventTarget {
return Promise.resolve();
};
}
if (name == 'getChapters') {
// This does not follow our standard pattern (takes an arguments), and
// therefore can't be proactively proxied and cached the way other
// synchronous getters can.
return () => {
shaka.log.alwaysWarn(name + '() does not work while casting!');
return [];
};
}
} // if (this.sender_.isCasting())
// If we are casting, but the first update has not come in yet, use local
-6
View File
@@ -440,12 +440,6 @@ shaka.cast.CastReceiver = class extends shaka.util.FakeEventTarget {
this.video_[k] = v;
}
for (const k in initState['playerAfterLoad']) {
const v = initState['playerAfterLoad'][k];
// All player state vars are setters to be called.
/** @type {Object} */(this.player_)[k](v);
}
// Restore original autoplay setting.
this.video_.autoplay = autoplay;
if (initState['manifest']) {
-19
View File
@@ -305,8 +305,6 @@ shaka.cast.CastUtils.VideoVoidMethods = [
shaka.cast.CastUtils.PlayerGetterMethods = new Map()
// NOTE: The 'drmInfo' property is not proxied, as it is very large.
.set('getAssetUri', 2)
.set('getAudioLanguages', 4)
.set('getAudioLanguagesAndRoles', 4)
.set('getBufferFullness', 1)
.set('getBufferedInfo', 2)
.set('getExpiration', 2)
@@ -315,13 +313,10 @@ shaka.cast.CastUtils.PlayerGetterMethods = new Map()
// NOTE: The 'getManifestParserFactory' property is not proxied, as it would
// not serialize.
.set('getPlaybackRate', 2)
.set('getTextLanguages', 4)
.set('getTextLanguagesAndRoles', 4)
.set('isAudioOnly', 10)
.set('isBuffering', 1)
.set('isInProgress', 1)
.set('isLive', 10)
.set('isTextTrackVisible', 1)
.set('isVideoOnly', 10)
.set('keySystem', 10)
.set('seekRange', 1)
@@ -380,16 +375,6 @@ shaka.cast.CastUtils.PlayerInitState = [
];
/**
* Player getter and setter methods that are used to transfer state after
* load() is resolved.
* @const {!Array<!Array<string>>}
*/
shaka.cast.CastUtils.PlayerInitAfterLoadState = [
['isTextTrackVisible', 'setTextTrackVisibility'],
];
/**
* Player methods with no return value that are proxied while casting.
* @const {!Array<string>}
@@ -398,15 +383,11 @@ shaka.cast.CastUtils.PlayerVoidMethods = [
'cancelTrickPlay',
'configure',
'configurationForLowLatency',
'getChapters',
'resetConfiguration',
'retryStreaming',
'selectAudioLanguage',
'selectAudioTrack',
'selectTextLanguage',
'selectTextTrack',
'selectVariantTrack',
'selectVariantsByLabel',
'selectVideoTrack',
'setTextTrackVisibility',
'trickPlay',
+1 -24
View File
@@ -8,7 +8,6 @@ goog.provide('shaka.dash.DashParser');
goog.require('goog.asserts');
goog.require('goog.Uri');
goog.require('shaka.Deprecate');
goog.require('shaka.abr.Ewma');
goog.require('shaka.dash.ContentProtection');
goog.require('shaka.dash.MpdUtils');
@@ -40,7 +39,6 @@ goog.require('shaka.util.StringUtils');
goog.require('shaka.util.TimeUtils');
goog.require('shaka.util.Timer');
goog.require('shaka.util.TXml');
goog.require('shaka.util.XmlUtils');
/**
@@ -468,27 +466,7 @@ shaka.dash.DashParser = class {
* @private
*/
async parseManifest_(data, finalManifestUri, rootElement) {
let manifestData = data;
const manifestPreprocessor = this.config_.dash.manifestPreprocessor;
const defaultManifestPreprocessor =
shaka.util.PlayerConfiguration.defaultManifestPreprocessor;
if (manifestPreprocessor != defaultManifestPreprocessor) {
shaka.Deprecate.deprecateFeature(5,
'manifest.dash.manifestPreprocessor configuration',
'Please Use manifest.dash.manifestPreprocessorTXml instead.');
const mpdElement =
shaka.util.XmlUtils.parseXml(manifestData, rootElement);
if (!mpdElement) {
throw new shaka.util.Error(
shaka.util.Error.Severity.CRITICAL,
shaka.util.Error.Category.MANIFEST,
shaka.util.Error.Code.DASH_INVALID_XML,
finalManifestUri);
}
manifestPreprocessor(mpdElement);
manifestData = shaka.util.XmlUtils.toArrayBuffer(mpdElement);
}
const mpd = shaka.util.TXml.parseXml(manifestData, rootElement);
const mpd = shaka.util.TXml.parseXml(data, rootElement);
if (!mpd) {
throw new shaka.util.Error(
shaka.util.Error.Severity.CRITICAL,
@@ -3276,7 +3254,6 @@ shaka.dash.DashParser = class {
endTime: endTime,
id: eventNode.attributes['id'] || '',
timescale: timescale,
eventElement: TXml.txmlNodeToDomElement(eventNode),
eventNode: TXml.cloneNode(eventNode),
};
-9
View File
@@ -6,8 +6,6 @@
goog.provide('shaka.dependencies');
goog.require('shaka.Deprecate');
/**
* @export
*/
@@ -24,12 +22,6 @@ shaka.dependencies = class {
if (!shaka.dependencies.Allowed[key]) {
throw new Error(`${key} is not supported`);
}
if (key == shaka.dependencies.Allowed.muxjs) {
shaka.Deprecate.deprecateFeature(5,
'mux.js',
'mux.js is no longer used in Shaka Player.');
return;
}
shaka.dependencies.dependencies_.set(key, () => dep);
}
@@ -56,7 +48,6 @@ shaka.dependencies = class {
* @enum {string}
*/
shaka.dependencies.Allowed = {
muxjs: 'muxjs',
ISOBoxer: 'ISOBoxer',
};
+7 -30
View File
@@ -6,7 +6,6 @@
goog.provide('shaka.lcevc.Dec');
goog.require('shaka.log');
goog.require('shaka.Deprecate');
goog.require('shaka.util.IReleasable');
goog.require('shaka.util.ManifestParserUtils');
@@ -51,9 +50,6 @@ shaka.lcevc.Dec = class {
/** @private {boolean} */
this.isDualTrack_ = isDualTrack;
/** @private {boolean} */
this.toBeDeprecated_ = false;
this.create_();
}
@@ -114,18 +110,10 @@ shaka.lcevc.Dec = class {
if (this.lcevcLib_.SupportObject.webGLSupport(this.canvas_)) {
// Make sure the canvas is not hidden from a previous playback session.
this.canvas_.classList.remove('shaka-hidden');
// Initiate LCEVC Dec Library based on the type of module available.
if (this.toBeDeprecated_) {
this.dec_ = new this.lcevcLib_.LcevcDil(
this.media_,
this.canvas_,
this.decConfig_);
} else {
this.dec_ = new this.lcevcLib_.LCEVCdec(
this.media_,
this.canvas_,
this.decConfig_);
}
this.dec_ = new this.lcevcLib_.LCEVCdec(
this.media_,
this.canvas_,
this.decConfig_);
}
}
}
@@ -159,16 +147,8 @@ shaka.lcevc.Dec = class {
if (typeof LCEVCdec !== 'undefined') {
this.lcevcLib_ = LCEVCdec;
} else {
if (typeof LcevcDil !== 'undefined') {
this.lcevcLib_ = LcevcDil;
this.toBeDeprecated_ = true;
shaka.Deprecate.deprecateFeature(5,
'LcevcDil',
'lcevc_dil.js is deprecated, please use lcevc_dec.js instead');
} else {
shaka.log.alwaysWarn('Could not find LCEVC Library on this page');
return false;
}
shaka.log.alwaysWarn('Could not find LCEVC Library on this page');
return false;
}
// Making Sure if there is a valid LCEVC Dec Library exists.
@@ -225,10 +205,7 @@ shaka.lcevc.Dec = class {
if (this.dec_) {
this.dec_.setLevelSwitching(stream.id, true);
this.dec_.setContainerFormat(containerFormat);
// This functionality is only available on the LCEVC Dec Library.
if (!this.toBeDeprecated_) {
this.dec_.setStreamingFormat(streamingFormat);
}
this.dec_.setStreamingFormat(streamingFormat);
}
}
-16
View File
@@ -6,7 +6,6 @@
goog.provide('shaka.media.ManifestParser');
goog.require('shaka.Deprecate');
goog.require('shaka.device.DeviceFactory');
goog.require('shaka.log');
goog.require('shaka.util.Error');
@@ -18,21 +17,6 @@ goog.require('shaka.util.Error');
* @export
*/
shaka.media.ManifestParser = class {
/**
* Registers a manifest parser by file extension.
*
* @param {string} extension The file extension of the manifest.
* @param {shaka.extern.ManifestParser.Factory} parserFactory The factory
* used to create parser instances.
* @export
*/
static registerParserByExtension(extension, parserFactory) {
shaka.Deprecate.deprecateFeature(5,
'ManifestParser.registerParserByExtension',
'Please use an ManifestParser with registerParserByMime function.');
}
/**
* Registers a manifest parser by MIME type.
*
+1 -23
View File
@@ -7,7 +7,6 @@
goog.provide('shaka.mss.MssParser');
goog.require('goog.asserts');
goog.require('shaka.Deprecate');
goog.require('shaka.abr.Ewma');
goog.require('shaka.log');
goog.require('shaka.media.InitSegmentReference');
@@ -27,7 +26,6 @@ goog.require('shaka.util.OperationManager');
goog.require('shaka.util.PlayerConfiguration');
goog.require('shaka.util.Timer');
goog.require('shaka.util.TXml');
goog.require('shaka.util.XmlUtils');
/**
@@ -298,27 +296,7 @@ shaka.mss.MssParser = class {
* @private
*/
parseManifest_(data, finalManifestUri) {
let manifestData = data;
const manifestPreprocessor = this.config_.mss.manifestPreprocessor;
const defaultManifestPreprocessor =
shaka.util.PlayerConfiguration.defaultManifestPreprocessor;
if (manifestPreprocessor != defaultManifestPreprocessor) {
shaka.Deprecate.deprecateFeature(5,
'manifest.mss.manifestPreprocessor configuration',
'Please Use manifest.mss.manifestPreprocessorTXml instead.');
const mssElement =
shaka.util.XmlUtils.parseXml(manifestData, 'SmoothStreamingMedia');
if (!mssElement) {
throw new shaka.util.Error(
shaka.util.Error.Severity.CRITICAL,
shaka.util.Error.Category.MANIFEST,
shaka.util.Error.Code.MSS_INVALID_XML,
finalManifestUri);
}
manifestPreprocessor(mssElement);
manifestData = shaka.util.XmlUtils.toArrayBuffer(mssElement);
}
const mss = shaka.util.TXml.parseXml(manifestData, 'SmoothStreamingMedia');
const mss = shaka.util.TXml.parseXml(data, 'SmoothStreamingMedia');
if (!mss) {
throw new shaka.util.Error(
shaka.util.Error.Severity.CRITICAL,
+34 -955
View File
File diff suppressed because it is too large Load Diff
+2 -4
View File
@@ -175,12 +175,10 @@ shaka.text.NativeTextDisplayer = class {
if (trackId > -1) {
this.player_.selectTextTrack(
/** @type {!shaka.extern.TextTrack} */({id: trackId}));
} else {
this.player_.selectTextTrack();
}
}
// The selectTextTrack() method does not accept null as parameter.
// So we need to use setTextTrackVisibility() if no track selected.
this.player_.setTextTrackVisibility(trackId > -1 &&
this.trackNodes_.get(trackId).track.mode === 'showing');
}).tickAfter(0);
};
-176
View File
@@ -1,176 +0,0 @@
/*! @license
* Shaka Player
* Copyright 2016 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @fileoverview
*/
goog.provide('shaka.text.SimpleTextDisplayer');
goog.require('shaka.Deprecate');
goog.require('shaka.text.Utils');
/**
* A text displayer plugin using the browser's native VTTCue interface.
*
* @implements {shaka.extern.TextDisplayer}
* @deprecated
* @export
*/
shaka.text.SimpleTextDisplayer = class {
/**
* @param {HTMLMediaElement} video
* @param {string} label
*/
constructor(video, label) {
shaka.Deprecate.deprecateFeature(5,
'SimpleTextDisplayer', 'Please migrate to NativeTextDisplayer');
/** @private {HTMLMediaElement} */
this.video_ = video;
/** @private {string} */
this.textTrackLabel_ = label;
/** @private {TextTrack} */
this.textTrack_ = null;
// TODO: Test that in all cases, the built-in CC controls in the video
// element are toggling our TextTrack.
// If the video element has TextTracks, disable them. If we see one that
// was created by a previous instance of Shaka Player, reuse it.
for (const track of Array.from(this.video_.textTracks)) {
if (track.kind === 'metadata' || track.kind === 'chapters') {
continue;
}
// NOTE: There is no API available to remove a TextTrack from a video
// element.
track.mode = 'disabled';
if (track.label == this.textTrackLabel_) {
this.textTrack_ = track;
}
}
if (this.textTrack_) {
this.textTrack_.mode = 'hidden';
}
}
/**
* @override
* @export
*/
configure(config) {
// Unused.
}
/**
* @override
* @export
*/
remove(start, end) {
// Check that the displayer hasn't been destroyed.
if (!this.textTrack_) {
return false;
}
const removeInRange = (cue) => {
const inside = cue.startTime < end && cue.endTime > start;
return inside;
};
shaka.text.Utils.removeCuesFromTextTrack(this.textTrack_, removeInRange);
return true;
}
/**
* @override
* @export
*/
append(cues) {
if (!this.textTrack_) {
return;
}
shaka.text.Utils.appendCuesToTextTrack(this.textTrack_, cues);
}
/**
* @override
* @export
*/
destroy() {
if (this.textTrack_) {
const removeIt = (cue) => true;
shaka.text.Utils.removeCuesFromTextTrack(this.textTrack_, removeIt);
// NOTE: There is no API available to remove a TextTrack from a video
// element.
this.textTrack_.mode = 'disabled';
}
this.video_ = null;
this.textTrack_ = null;
return Promise.resolve();
}
/**
* @override
* @export
*/
isTextVisible() {
if (!this.textTrack_) {
return false;
}
return this.textTrack_.mode == 'showing';
}
/**
* @override
* @export
*/
setTextVisibility(on) {
if (on && !this.textTrack_) {
this.createTextTrack_();
}
if (this.textTrack_) {
this.textTrack_.mode = on ? 'showing' : 'hidden';
}
}
/**
* @override
* @export
*/
setTextLanguage(language) {
}
/**
* @override
* @export
*/
enableTextDisplayer() {
this.createTextTrack_();
}
/**
* @private
*/
createTextTrack_() {
if (this.video_ && !this.textTrack_) {
// As far as I can tell, there is no observable difference between setting
// kind to 'subtitles' or 'captions' when creating the TextTrack object.
// The individual text tracks from the manifest will still have their own
// kinds which can be displayed in the app's UI.
this.textTrack_ =
this.video_.addTextTrack('subtitles', this.textTrackLabel_);
this.textTrack_.mode = 'hidden';
}
}
};
+2 -15
View File
@@ -7,7 +7,6 @@
goog.provide('shaka.text.TextEngine');
goog.require('goog.asserts');
goog.require('shaka.Deprecate');
goog.require('shaka.media.ClosedCaptionParser');
goog.require('shaka.text.Cue');
goog.require('shaka.util.BufferUtils');
@@ -149,20 +148,8 @@ shaka.text.TextEngine = class {
goog.asserts.assert(
factory, 'Text type negotiation should have happened already');
this.parser_ = factory();
if (this.parser_.setSequenceMode) {
this.parser_.setSequenceMode(sequenceMode);
} else {
shaka.Deprecate.deprecateFeature(5,
'Text parsers w/ setSequenceMode',
'Text parsers should have a "setSequenceMode" method!');
}
if (this.parser_.setManifestType) {
this.parser_.setManifestType(manifestType);
} else {
shaka.Deprecate.deprecateFeature(5,
'Text parsers w/ setManifestType',
'Text parsers should have a "setManifestType" method!');
}
this.parser_.setSequenceMode(sequenceMode);
this.parser_.setManifestType(manifestType);
this.segmentRelativeVttTiming_ = segmentRelativeVttTiming;
}
-20
View File
@@ -1,20 +0,0 @@
/*! @license
* Shaka Player
* Copyright 2016 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
goog.provide('shaka.util.FairPlayUtils');
goog.require('shaka.drm.FairPlay');
/**
* @summary A set of FairPlay utility functions. DEPRECATED: Please use
* shaka.drm.FairPlay instead.
* @deprecated
* @export
*/
shaka.util.FairPlayUtils = class extends shaka.drm.FairPlay {
// DEPRECATED
};
-1
View File
@@ -195,7 +195,6 @@ shaka.util.FakeEvent.EventName = {
StateChanged: 'statechanged',
Streaming: 'streaming',
TextChanged: 'textchanged',
TextTrackVisibility: 'texttrackvisibility',
ThirdQuartile: 'thirdquartile',
TimelineRegionAdded: 'timelineregionadded',
TimelineRegionEnter: 'timelineregionenter',
-14
View File
@@ -149,8 +149,6 @@ shaka.util.PlayerConfiguration = class {
'urn:uuid:3d5e6d35-9b9a-41e8-b843-dd3c6e72c42c':
'com.huawei.wiseplay',
},
manifestPreprocessor:
shaka.util.PlayerConfiguration.defaultManifestPreprocessor,
manifestPreprocessorTXml:
shaka.util.PlayerConfiguration.defaultManifestPreprocessorTXml,
sequenceMode: false,
@@ -175,8 +173,6 @@ shaka.util.PlayerConfiguration = class {
allowRangeRequestsToGuessMimeType: false,
},
mss: {
manifestPreprocessor:
shaka.util.PlayerConfiguration.defaultManifestPreprocessor,
manifestPreprocessorTXml:
shaka.util.PlayerConfiguration.defaultManifestPreprocessorTXml,
sequenceMode: false,
@@ -681,16 +677,6 @@ shaka.util.PlayerConfiguration = class {
return selectedTracks;
}
/**
* @param {!Element} element
* @return {!Element}
*/
static defaultManifestPreprocessor(element) {
return shaka.util.ConfigUtils.referenceParametersAndReturn(
[element],
element);
}
/**
* @param {!shaka.extern.xml.Node} element
* @return {!shaka.extern.xml.Node}
-33
View File
@@ -894,39 +894,6 @@ shaka.util.TXml = class {
}
}
/**
* Converts a tXml node to DOM element.
* @param {shaka.extern.xml.Node} node
* @return {!Element}
*/
static txmlNodeToDomElement(node) {
const TXml = shaka.util.TXml;
let namespace = '';
const parts = node.tagName.split(':');
if (parts.length > 0) {
namespace = TXml.getKnownSchema(parts[0]);
}
const element = document.createElementNS(namespace, node.tagName);
for (const k in node.attributes) {
const v = node.attributes[k];
element.setAttribute(k, v);
}
for (const child of node.children) {
let childElement;
if (typeof child == 'string') {
childElement = new Text(child);
} else {
childElement = TXml.txmlNodeToDomElement(child);
}
element.appendChild(childElement);
}
return element;
}
/**
* Clones node and its children recursively. Skips parent.
* @param {?shaka.extern.xml.Node} node
-40
View File
@@ -7,7 +7,6 @@
goog.provide('shaka.util.TsParser');
goog.require('goog.asserts');
goog.require('shaka.Deprecate');
goog.require('shaka.log');
goog.require('shaka.util.ExpGolomb');
goog.require('shaka.util.Id3Utils');
@@ -523,28 +522,6 @@ shaka.util.TsParser = class {
return pes;
}
/**
* Parse AVC Nalus
*
* The code is based on hls.js
* Credit to https://github.com/video-dev/hls.js/blob/master/src/demux/tsdemuxer.ts
*
* @param {shaka.extern.MPEG_PES} pes
* @param {?shaka.extern.MPEG_PES=} nextPes
* @return {!Array<shaka.extern.VideoNalu>}
* @export
*/
parseAvcNalus(pes, nextPes) {
shaka.Deprecate.deprecateFeature(5,
'TsParser.parseAvcNalus',
'Please use parseNalus function instead.');
const lastInfo = {
nalu: null,
state: null,
};
return this.parseNalus(pes, lastInfo);
}
/**
* Parse AVC and HVC Nalus
*
@@ -868,23 +845,6 @@ shaka.util.TsParser = class {
return nalus;
}
/**
* Return the video resolution
*
* @return {{height: ?string, width: ?string}}
* @export
*/
getVideoResolution() {
shaka.Deprecate.deprecateFeature(5,
'TsParser.getVideoResolution',
'Please use getVideoInfo function instead.');
const videoInfo = this.getVideoInfo();
return {
height: videoInfo.height,
width: videoInfo.width,
};
}
/**
* Return the video information
*
-1
View File
@@ -77,7 +77,6 @@ submenuopen
textchanged
textlang
textrole
texttrackvisibility
thirdquartile
timeandseekrangeupdated
timelineregionadded
+2 -2
View File
@@ -12,10 +12,10 @@ Candidate features for future release cycles:
- Background fetch for offline storage
https://github.com/shaka-project/shaka-player/issues/879
v5.0
v6.0
- Conversion to Typescript (Smaller, more modular binary)
v4.17 - 2025 Q4
v5.0 - 2025 Q4
- Add automatic subtitles with translations (Experimental and disabled by default)
https://github.com/shaka-project/shaka-player/issues/9110
- Change dvvC box to free box for Dolby Vision workarounds
-1
View File
@@ -137,5 +137,4 @@ goog.require('shaka.ui.VRWebgl');
goog.require('shaka.ui.Watermark');
goog.require('shaka.util.Dom');
goog.require('shaka.util.Error');
goog.require('shaka.util.FairPlayUtils');
goog.require('shaka.util.Iterables');
-7
View File
@@ -1181,7 +1181,6 @@ describe('Interstitial Ad manager', () => {
id: 'PREROLL',
schemeIdUri: 'urn:mpeg:dash:event:alternativeMPD:insert:2025',
eventNode,
eventElement: TXml.txmlNodeToDomElement(eventNode),
value: '',
timescale: 1,
};
@@ -1216,7 +1215,6 @@ describe('Interstitial Ad manager', () => {
id: 'PREROLL',
schemeIdUri: 'urn:mpeg:dash:event:alternativeMPD:replace:2025',
eventNode,
eventElement: TXml.txmlNodeToDomElement(eventNode),
value: '',
timescale: 1,
};
@@ -1253,7 +1251,6 @@ describe('Interstitial Ad manager', () => {
id: 'PREROLL',
schemeIdUri: 'urn:mpeg:dash:event:alternativeMPD:insert:2025',
eventNode,
eventElement: TXml.txmlNodeToDomElement(eventNode),
value: '',
timescale: 1,
};
@@ -1283,7 +1280,6 @@ describe('Interstitial Ad manager', () => {
id: 'OVERLAY',
schemeIdUri: 'urn:mpeg:dash:event:2012',
eventNode,
eventElement: TXml.txmlNodeToDomElement(eventNode),
value: '',
timescale: 1,
};
@@ -1356,7 +1352,6 @@ describe('Interstitial Ad manager', () => {
id: 'OVERLAY',
schemeIdUri: 'urn:mpeg:dash:event:2012',
eventNode,
eventElement: TXml.txmlNodeToDomElement(eventNode),
value: '',
timescale: 1,
};
@@ -1386,7 +1381,6 @@ describe('Interstitial Ad manager', () => {
id: 'OVERLAY',
schemeIdUri: 'urn:scte:dash:scte214-events',
eventNode,
eventElement: TXml.txmlNodeToDomElement(eventNode),
value: '',
timescale: 1,
};
@@ -1477,7 +1471,6 @@ describe('Interstitial Ad manager', () => {
id: 'OVERLAY',
schemeIdUri: 'urn:scte:dash:scte214-events',
eventNode,
eventElement: TXml.txmlNodeToDomElement(eventNode),
value: '',
timescale: 1,
};
+1 -14
View File
@@ -316,7 +316,6 @@ describe('CastProxy', () => {
// Local values that will be ignored:
const fakeConfig = {key: 'value'};
mockPlayer.getConfiguration.and.returnValue(fakeConfig);
mockPlayer.isTextTrackVisible.and.returnValue(false);
// Set up the sender in casting mode:
mockSender.isCasting.and.returnValue(true);
@@ -326,7 +325,6 @@ describe('CastProxy', () => {
const fakeConfig2 = {key2: 'value2'};
const cache = {player: {
getConfiguration: fakeConfig2,
isTextTrackVisible: true,
trickPlay: jasmine.createSpy('trickPlay'),
}};
mockSender.get.and.callFake((targetName, property) => {
@@ -342,7 +340,6 @@ describe('CastProxy', () => {
});
expect(proxy.getPlayer().getConfiguration()).toEqual(fakeConfig2);
expect(proxy.getPlayer().isTextTrackVisible()).toBe(true);
// Call a method:
expect(mockPlayer.trickPlay).not.toHaveBeenCalled();
@@ -355,7 +352,6 @@ describe('CastProxy', () => {
it('returns local values when we have no remote values yet', () => {
const fakeConfig = {key: 'value'};
mockPlayer.getConfiguration.and.returnValue(fakeConfig);
mockPlayer.isTextTrackVisible.and.returnValue(true);
// Set up the sender in casting mode, but without any remote values:
mockSender.isCasting.and.returnValue(true);
@@ -371,7 +367,6 @@ describe('CastProxy', () => {
// Without remote values, we should still return the local ones.
expect(proxy.getPlayer().getConfiguration()).toEqual(fakeConfig);
expect(proxy.getPlayer().isTextTrackVisible()).toBe(true);
// Call a method:
expect(mockPlayer.trickPlay).not.toHaveBeenCalled();
@@ -494,7 +489,6 @@ describe('CastProxy', () => {
},
player: {
getConfiguration: {key: 'value'},
isTextTrackVisible: true,
},
};
mockSender.get.and.callFake((targetName, property) => {
@@ -509,7 +503,6 @@ describe('CastProxy', () => {
it('transfers remote state back to local objects', async () => {
// Nothing has been set yet:
expect(mockPlayer.configure).not.toHaveBeenCalled();
expect(mockPlayer.setTextTrackVisibility).not.toHaveBeenCalled();
expect(mockVideo.loop).toBe(false);
expect(mockVideo.playbackRate).toBe(1);
@@ -520,14 +513,11 @@ describe('CastProxy', () => {
expect(mockPlayer.configure).toHaveBeenCalledWith(
cache.player.getConfiguration);
// Nothing else yet:
expect(mockPlayer.setTextTrackVisibility).not.toHaveBeenCalled();
expect(mockVideo.loop).toBe(false);
expect(mockVideo.playbackRate).toBe(1);
// The rest is done async:
await shaka.test.Util.shortDelay();
expect(mockPlayer.setTextTrackVisibility).toHaveBeenCalledWith(
cache.player.isTextTrackVisible);
expect(mockVideo.loop).toBe(cache.video.loop);
expect(mockVideo.playbackRate).toBe(cache.video.playbackRate);
});
@@ -580,8 +570,6 @@ describe('CastProxy', () => {
expect(mockVideo.play).not.toHaveBeenCalled();
// State was still transferred, though:
expect(mockPlayer.setTextTrackVisibility).toHaveBeenCalledWith(
cache.player.isTextTrackVisible);
expect(mockVideo.loop).toBe(cache.video.loop);
expect(mockVideo.playbackRate).toBe(cache.video.playbackRate);
});
@@ -674,8 +662,7 @@ describe('CastProxy', () => {
getAssetUri: jasmine.createSpy('getAssetUri'),
getConfiguration: jasmine.createSpy('getConfiguration'),
configure: jasmine.createSpy('configure'),
isTextTrackVisible: jasmine.createSpy('isTextTrackVisible'),
setTextTrackVisibility: jasmine.createSpy('setTextTrackVisibility'),
selectTextTrack: jasmine.createSpy('selectTextTrack'),
trickPlay: jasmine.createSpy('trickPlay'),
destroy: jasmine.createSpy('destroy'),
addEventListener: (eventName, listener) => {
-3
View File
@@ -99,9 +99,6 @@ filterDescribe('CastReceiver', castReceiverIntegrationSupport, () => {
player: {
configure: {},
},
playerAfterLoad: {
setTextTrackVisibility: true,
},
video: {
loop: true,
playbackRate: 5,
-8
View File
@@ -249,9 +249,6 @@ filterDescribe('CastReceiver', castReceiverSupport, () => {
player: {
configure: fakeConfig,
},
playerAfterLoad: {
setTextTrackVisibility: true,
},
video: {
loop: true,
playbackRate: 5,
@@ -275,14 +272,11 @@ filterDescribe('CastReceiver', castReceiverSupport, () => {
// App data next:
expect(mockAppDataCallback).toHaveBeenCalledWith(fakeAppData);
// Nothing else yet:
expect(mockPlayer.setTextTrackVisibility).not.toHaveBeenCalled();
expect(mockVideo.loop).toBe(false);
expect(mockVideo.playbackRate).toBe(1);
// The rest is done async:
await shaka.test.Util.shortDelay();
expect(mockPlayer.setTextTrackVisibility).toHaveBeenCalledWith(
fakeInitState.playerAfterLoad.setTextTrackVisibility);
expect(mockVideo.loop).toBe(fakeInitState.video.loop);
expect(mockVideo.playbackRate).toBe(fakeInitState.video.playbackRate);
});
@@ -392,8 +386,6 @@ filterDescribe('CastReceiver', castReceiverSupport, () => {
expect(mockVideo.play).not.toHaveBeenCalled();
// State was still transferred, though:
expect(mockPlayer.setTextTrackVisibility).toHaveBeenCalledWith(
fakeInitState.playerAfterLoad.setTextTrackVisibility);
expect(mockVideo.loop).toBe(fakeInitState.video.loop);
expect(mockVideo.playbackRate).toBe(fakeInitState.video.playbackRate);
});
-2
View File
@@ -1332,7 +1332,6 @@ describe('DashParser Live', () => {
endTime: 60,
id: '',
timescale: 100,
eventElement: jasmine.any(Element),
eventNode: jasmine.any(Object),
});
expect(onTimelineRegionAddedSpy).toHaveBeenCalledWith({
@@ -1342,7 +1341,6 @@ describe('DashParser Live', () => {
endTime: 23,
id: 'abc',
timescale: 100,
eventElement: jasmine.any(Element),
eventNode: jasmine.any(Object),
});
});
-1
View File
@@ -365,7 +365,6 @@ describe('RegionObserver', () => {
startTime: startTimeSeconds,
endTime: endTimeSeconds,
timescale: 1,
eventElement: null,
eventNode: null,
};
}
-1
View File
@@ -134,7 +134,6 @@ describe('RegionTimeline', () => {
startTime: startTimeSeconds,
endTime: endTimeSeconds,
timescale: 1,
eventElement: null,
eventNode: null,
};
}
+24 -165
View File
@@ -306,145 +306,6 @@ describe('Player', () => {
});
}); // describe('getStats')
describe('setTextTrackVisibility', () => {
// Repro for https://github.com/shaka-project/shaka-player/issues/1879.
it('appends cues when enabled initially', async () => {
let cues = [];
/** @const {!shaka.test.FakeTextDisplayer} */
const displayer = new shaka.test.FakeTextDisplayer();
displayer.appendSpy.and.callFake((added) => {
cues = cues.concat(added);
});
player.configure('textDisplayFactory', () => displayer);
const preferredTextLanguage = 'fa'; // The same as in the content itself
player.configure({preferredTextLanguage: preferredTextLanguage});
await player.load('test:sintel_realistic_compiled');
// Play until a time at which the external cues would be on screen.
await video.play();
await waiter.waitUntilPlayheadReachesOrFailOnTimeout(video, 4, 20);
expect(player.isTextTrackVisible()).toBe(true);
expect(displayer.isTextVisible()).toBe(true);
expect(cues.length).toBeGreaterThan(0);
});
it('appends cues for external text', async () => {
let cues = [];
/** @const {!shaka.test.FakeTextDisplayer} */
const displayer = new shaka.test.FakeTextDisplayer();
displayer.appendSpy.and.callFake((added) => {
cues = cues.concat(added);
});
player.configure('textDisplayFactory', () => displayer);
await player.load('test:sintel_no_text_compiled');
const locationUri = new goog.Uri(location.href);
const partialUri = new goog.Uri('/base/test/test/assets/text-clip.vtt');
const absoluteUri = locationUri.resolve(partialUri);
const newTrack = await player.addTextTrackAsync(
absoluteUri.toString(), 'en', 'subtitles', 'text/vtt');
expect(player.getTextTracks()).toEqual([newTrack]);
player.selectTextTrack(newTrack);
player.setTextTrackVisibility(true);
await waiter.waitForEvent(player, 'texttrackvisibility');
// Play until a time at which the external cues would be on screen.
await video.play();
await waiter.waitUntilPlayheadReachesOrFailOnTimeout(video, 4, 20);
expect(player.isTextTrackVisible()).toBe(true);
expect(displayer.isTextVisible()).toBe(true);
expect(cues.length).toBeGreaterThan(0);
});
// https://github.com/shaka-project/shaka-player/issues/2553
it('does not change the selected track', async () => {
await player.load('test:forced_subs_simulation_compiled');
// In this content, both text tracks have the same language and role, and
// so should look identical in terms of choosing one to match a
// preference. This is important to the test, so verify it first.
const tracks = player.getTextTracks();
expect(tracks[0].language).toBe(tracks[1].language);
expect(tracks[0].roles).toEqual(tracks[1].roles);
const getTracksActive = () => player.getTextTracks().map((t) => t.active);
// If we choose a track first, then turn on text, the track should not
// change. Try this with both tracks.
player.setTextTrackVisibility(false);
player.selectTextTrack(tracks[0]);
expect(getTracksActive()).toEqual([true, false]);
player.setTextTrackVisibility(true);
expect(getTracksActive()).toEqual([true, false]);
player.setTextTrackVisibility(false);
player.selectTextTrack(tracks[1]);
expect(getTracksActive()).toEqual([false, true]);
player.setTextTrackVisibility(true);
expect(getTracksActive()).toEqual([false, true]);
});
// https://github.com/shaka-project/shaka-player/issues/4821
it('loads a single text stream', async () => {
/** @type {!jasmine.Spy} */
const textchanged = jasmine.createSpy('listener');
player.addEventListener('textchanged', Util.spyFunc(textchanged));
player.configure({preferredTextLanguage: 'en'});
await player.load('test:sintel_no_text_compiled');
textchanged.calls.reset();
// Add preferred language text track.
const locationUri = new goog.Uri(location.href);
const partialUri = new goog.Uri('/base/test/test/assets/text-clip.vtt');
const absoluteUri = locationUri.resolve(partialUri);
await player.addTextTrackAsync(
absoluteUri.toString(), 'en', 'subtitles', 'text/vtt');
expect(textchanged).toHaveBeenCalledTimes(1);
// Add alternate language text track.
// Two text tracks with same timings but different text
// are necessary for test.
const partialUri2 =
new goog.Uri('/base/test/test/assets/text-clip-alt.vtt');
const absoluteUri2 = locationUri.resolve(partialUri2);
await player.addTextTrackAsync(
absoluteUri2.toString(), 'fr', 'subtitles', 'text/vtt');
expect(textchanged).toHaveBeenCalledTimes(2);
const textTracks = player.getTextTracks();
expect(textTracks.length).toBe(2);
expect(textTracks[0].language).toBe('en');
expect(textTracks[1].language).toBe('fr');
// Enable text visibility and immediately change language.
// Only one set of cues should be active.
// Cues should be of the selected language track.
player.setTextTrackVisibility(true);
player.selectTextLanguage('fr');
video.currentTime = 5;
await video.play();
await waiter.waitForMovementOrFailOnTimeout(video, 10);
expect(video.textTracks[1].activeCues.length).toBe(1);
expect(player.getTextTracks()[1].active).toBe(true);
});
}); // describe('setTextTrackVisibility')
describe('autoShowText', () => {
async function textMatchesAudioDoesNot() {
const preferredTextLanguage = 'fa'; // The same as in the content
@@ -519,17 +380,20 @@ describe('Player', () => {
it('enables text if text matches and audio does not', async () => {
await textMatchesAudioDoesNot();
expect(player.isTextTrackVisible()).toBe(true);
const activeTextTrack = player.getTextTracks().find((t) => t.active);
expect(activeTextTrack).toBeDefined();
});
it('disables text if text does not match', async () => {
await textDoesNotMatch();
expect(player.isTextTrackVisible()).toBe(false);
const activeTextTrack = player.getTextTracks().find((t) => t.active);
expect(activeTextTrack).toBeUndefined();
});
it('disables text if both text and audio match', async () => {
await textAndAudioMatch();
expect(player.isTextTrackVisible()).toBe(false);
const activeTextTrack = player.getTextTracks().find((t) => t.active);
expect(activeTextTrack).toBeUndefined();
});
}); // IF_SUBTITLES_MAY_BE_NEEDED
@@ -542,17 +406,20 @@ describe('Player', () => {
it('enables text if text matches and audio does not', async () => {
await textMatchesAudioDoesNot();
expect(player.isTextTrackVisible()).toBe(true);
const activeTextTrack = player.getTextTracks().find((t) => t.active);
expect(activeTextTrack).toBeDefined();
});
it('disables text if text does not match', async () => {
await textDoesNotMatch();
expect(player.isTextTrackVisible()).toBe(false);
const activeTextTrack = player.getTextTracks().find((t) => t.active);
expect(activeTextTrack).toBeUndefined();
});
it('enables text if both text and audio match', async () => {
await textAndAudioMatch();
expect(player.isTextTrackVisible()).toBe(true);
const activeTextTrack = player.getTextTracks().find((t) => t.active);
expect(activeTextTrack).toBeDefined();
});
}); // IF_PREFERRED_TEXT_LANGUAGE
@@ -563,17 +430,20 @@ describe('Player', () => {
it('enables text if text matches and audio does not', async () => {
await textMatchesAudioDoesNot();
expect(player.isTextTrackVisible()).toBe(true);
const activeTextTrack = player.getTextTracks().find((t) => t.active);
expect(activeTextTrack).toBeDefined();
});
it('enables text if text does not match', async () => {
await textDoesNotMatch();
expect(player.isTextTrackVisible()).toBe(true);
const activeTextTrack = player.getTextTracks().find((t) => t.active);
expect(activeTextTrack).toBeDefined();
});
it('enables text if both text and audio match', async () => {
await textAndAudioMatch();
expect(player.isTextTrackVisible()).toBe(true);
const activeTextTrack = player.getTextTracks().find((t) => t.active);
expect(activeTextTrack).toBeDefined();
});
}); // ALWAYS
@@ -584,17 +454,20 @@ describe('Player', () => {
it('disables text if text matches and audio does not', async () => {
await textMatchesAudioDoesNot();
expect(player.isTextTrackVisible()).toBe(false);
const activeTextTrack = player.getTextTracks().find((t) => t.active);
expect(activeTextTrack).toBeUndefined();
});
it('disables text if text does not match', async () => {
await textDoesNotMatch();
expect(player.isTextTrackVisible()).toBe(false);
const activeTextTrack = player.getTextTracks().find((t) => t.active);
expect(activeTextTrack).toBeUndefined();
});
it('disables text if both text and audio match', async () => {
await textAndAudioMatch();
expect(player.isTextTrackVisible()).toBe(false);
const activeTextTrack = player.getTextTracks().find((t) => t.active);
expect(activeTextTrack).toBeUndefined();
});
}); // NEVER
}); // AutoShowText
@@ -724,20 +597,6 @@ describe('Player', () => {
});
}); // describe('TextDisplayer plugin')
describe('TextAndRoles', () => {
// Regression Test. Makes sure that the language and role fields have been
// properly exported from the player.
it('exports language and roles fields', async () => {
await player.load('test:sintel_compiled');
const languagesAndRoles = player.getTextLanguagesAndRoles();
expect(languagesAndRoles.length).toBeTruthy();
for (const languageAndRole of languagesAndRoles) {
expect(languageAndRole.language).not.toBeUndefined();
expect(languageAndRole.role).not.toBeUndefined();
}
});
}); // describe('TextAndRoles')
describe('streaming event', () => {
// Calling switch early during load() caused a failed assertion in Player
// and the track selection was ignored. Because this bug involved
+1 -1
View File
@@ -110,7 +110,7 @@ describe('Player Src Equals', () => {
player.configure('preferredAudioLanguage', 'de');
player.configure('preferredTextLanguage', 'el');
player.setTextTrackVisibility(true);
player.configure('autoShowText', shaka.config.AutoShowText.ALWAYS);
await loadWithSrcEquals(HLS_CONTENT_URI);
+4 -10
View File
@@ -277,19 +277,13 @@ describe('Player Src Equals', () => {
// On platforms with audioTracks, such as Safari, we get one track, with
// language set to whatever is in the mp4.
if (video.audioTracks) {
expect(player.getAudioLanguages()).toEqual(['en']);
// Note that some browsers, such as Safari, say this is the 'main'
// role, while others, such as Edge, do not. For the purposes of this
// test, it doesn't matter what the role is.
expect(player.getAudioLanguagesAndRoles()).toEqual(
[{language: 'en', role: jasmine.any(String), label: null}]);
expect(player.getAudioTracks())
.toEqual([jasmine.objectContaining({language: 'en'})]);
} else {
expect(player.getAudioLanguages()).toEqual([]);
expect(player.getAudioLanguagesAndRoles()).toEqual([]);
expect(player.getAudioTracks()).toEqual([]);
}
expect(player.getTextLanguages()).toEqual([]);
expect(player.getTextLanguagesAndRoles()).toEqual([]);
expect(player.getTextTracks()).toEqual([]);
});
// Even though we loaded content using |src=| we should still be able to get
+60 -363
View File
@@ -679,39 +679,6 @@ describe('Player', () => {
});
});
describe('setTextTrackVisibility', () => {
beforeEach(() => {
manifest = shaka.test.ManifestGenerator.generate((manifest) => {
manifest.addVariant(0, (variant) => {
variant.addAudio(1);
variant.addVideo(2);
});
manifest.addTextStream(3, (stream) => {
stream.bandwidth = 100;
stream.kind = 'caption';
stream.label = 'Spanish';
stream.language = 'es';
});
});
});
it('load text stream if caption is visible', async () => {
await player.setTextTrackVisibility(true);
await player.load(fakeManifestUri, 0, fakeMimeType);
expect(streamingEngine.switchTextStream).toHaveBeenCalled();
expect(shaka.test.Util.invokeSpy(streamingEngine.getCurrentTextStream))
.not.toBe(null);
});
it('does not load text stream if caption is invisible', async () => {
await player.setTextTrackVisibility(false);
await player.load(fakeManifestUri, 0, fakeMimeType);
expect(streamingEngine.switchTextStream).not.toHaveBeenCalled();
expect(shaka.test.Util.invokeSpy(streamingEngine.getCurrentTextStream))
.toBe(null);
});
});
describe('when config.streaming.preferNativeDash is set to true', () => {
beforeAll(() => {
shaka.media.ManifestParser.registerParserByMime(
@@ -2494,13 +2461,15 @@ describe('Player', () => {
expect(getActiveTextTrack().id).toBe(englishTextTrack.id);
});
it('selectAudioLanguage() takes precedence over ' +
it('selectAudioTrack() takes precedence over ' +
'preferredAudioLanguage', () => {
// This preference is set in beforeEach, before load().
expect(player.getConfiguration().preferredAudioLanguage).toBe('en');
expect(getActiveVariantTrack().language).toBe('en');
player.selectAudioLanguage('es');
const newAudioTrack = audioTracks.find((t) => t.language == 'es');
goog.asserts.assert(newAudioTrack, 'audio track must be non-null');
player.selectAudioTrack(newAudioTrack);
expect(streamingEngine.switchVariant).toHaveBeenCalled();
const args = streamingEngine.switchVariant.calls.argsFor(0);
@@ -2509,10 +2478,13 @@ describe('Player', () => {
expect(getActiveVariantTrack().language).toBe('es');
});
it('selectAudioLanguage() respects selected role', () => {
it('selectAudioTrack() respects selected role', () => {
expect(getActiveVariantTrack().roles).not.toContain('commentary');
player.selectAudioLanguage('en', 'commentary');
const newAudioTrack = audioTracks.find((t) =>
t.language == 'en' && t.roles.includes('commentary'));
goog.asserts.assert(newAudioTrack, 'audio track must be non-null');
player.selectAudioTrack(newAudioTrack);
expect(streamingEngine.switchVariant).toHaveBeenCalled();
const args = streamingEngine.switchVariant.calls.argsFor(0);
@@ -2521,115 +2493,61 @@ describe('Player', () => {
expect(getActiveVariantTrack().roles).toContain('commentary');
});
it('selectAudioLanguage() ignores unplayable variants', () => {
player.configure({
restrictions: {minChannelsCount: 6},
});
player.selectAudioLanguage('es');
expect(getActiveVariantTrack().channelsCount).toBe(6);
});
it('selectAudioLanguage() respects selected audio codec', () => {
player.selectAudioLanguage('es', '', 0, 0, 'mp4a.40.2');
it('selectAudioTrack() respects selected audio codec', () => {
let newAudioTrack = audioTracks.find((t) =>
t.language == 'es' && t.codecs == 'mp4a.40.2');
goog.asserts.assert(newAudioTrack, 'audio track must be non-null');
player.selectAudioTrack(newAudioTrack);
expect(getActiveVariantTrack().audioCodec).toBe('mp4a.40.2');
player.selectAudioLanguage('es', '', 0, 0, 'ec-3');
newAudioTrack = audioTracks.find((t) =>
t.language == 'es' && t.codecs == 'ec-3');
goog.asserts.assert(newAudioTrack, 'audio track must be non-null');
player.selectAudioTrack(newAudioTrack);
expect(getActiveVariantTrack().audioCodec).toBe('ec-3');
});
it('selectAudioLanguage() applies role only to audio', () => {
it('selectAudioTrack() applies role only to audio', () => {
expect(getActiveVariantTrack().roles).not.toContain('commentary');
const videoRoles = getActiveVariantTrack().videoRoles;
player.selectAudioLanguage('en', 'commentary');
let newAudioTrack = audioTracks.find((t) =>
t.language == 'en' && t.roles.includes('commentary'));
goog.asserts.assert(newAudioTrack, 'audio track must be non-null');
player.selectAudioTrack(newAudioTrack);
let args = streamingEngine.switchVariant.calls.argsFor(0);
expect(args[0].audio.roles).toContain('commentary');
expect(args[0].video.roles).toBe(videoRoles);
// Switch audio role from 'commentary' to 'main'.
streamingEngine.switchVariant.calls.reset();
player.selectAudioLanguage('en', 'main');
newAudioTrack = audioTracks.find((t) =>
t.language == 'en' && t.roles.includes('main'));
goog.asserts.assert(newAudioTrack, 'audio track must be non-null');
player.selectAudioTrack(newAudioTrack);
expect(streamingEngine.switchVariant).toHaveBeenCalled();
args = streamingEngine.switchVariant.calls.argsFor(0);
expect(args[0].audio.roles).toContain('main');
expect(args[0].video.roles).toBe(videoRoles);
});
it('selectAudioLanguage() does not change selected text track', () => {
it('selectAudioTrack() does not change selected text track', () => {
// This came up in a custom application that allows to select
// from all tracks regardless of selected language.
// We imitate this behavior by calling selectTextLanguage()
// We imitate this behavior by calling selectTextTrack()
// with one language and then selecting a track in a different
// language.
player.selectTextLanguage('en');
const spanishTextTrack = textTracks.filter((t) => t.language == 'es')[0];
player.selectTextTrack(spanishTextTrack);
player.selectAudioLanguage('es');
expect(getActiveTextTrack().id).toBe(spanishTextTrack.id);
});
// Regression test for https://github.com/shaka-project/shaka-player/issues/2906
// and https://github.com/shaka-project/shaka-player/issues/2909.
it('selectAudioLanguage() can choose role-less tracks', async () => {
// For this test, we use a different (and simpler) manifest.
// Both audio tracks are English; one has a role, and one has no roles.
// The role=description track comes first to reproduce the conditions in
// #2909.
manifest = shaka.test.ManifestGenerator.generate((manifest) => {
manifest.addVariant(100, (variant) => {
variant.bandwidth = 1300;
variant.language = 'en';
variant.addVideo(1, (stream) => {
stream.originalId = 'video';
stream.bandwidth = 1000;
stream.width = 100;
stream.height = 200;
stream.frameRate = 1000000 / 42000;
stream.pixelAspectRatio = '59:54';
stream.roles = [];
});
variant.addAudio(2, (stream) => {
stream.originalId = 'audio-en-description';
stream.bandwidth = 100;
stream.channelsCount = 2;
stream.audioSamplingRate = 48000;
stream.roles = ['description'];
});
});
manifest.addVariant(101, (variant) => {
variant.bandwidth = 2300;
variant.language = 'en';
variant.addExistingStream(1); // video
variant.addAudio(3, (stream) => {
stream.originalId = 'audio-en';
stream.bandwidth = 100;
stream.channelsCount = 2;
stream.audioSamplingRate = 48000;
stream.roles = [];
});
});
});
// No explicit preferred audio language is also part of #2909.
player.configure('preferredAudioLanguage', undefined);
// Load again to get this test-specific manifest loaded.
await player.load(fakeManifestUri, 0, fakeMimeType);
// #2909: The initial choice should be for the role-less track, even
// though it is second in the manifest.
expect(getActiveVariantTrack().audioRoles).toEqual([]);
player.selectAudioLanguage('en', 'description');
expect(getActiveVariantTrack().audioRoles).toEqual(['description']);
// #2906: Selecting no particular role should prefer the track without any
// roles.
player.selectAudioLanguage('en');
expect(getActiveVariantTrack().audioRoles).toEqual([]);
let newTextTrack = textTracks.find((t) => t.language == 'en');
player.selectTextTrack(newTextTrack);
newTextTrack = textTracks.find((t) => t.language == 'es');
player.selectTextTrack(newTextTrack);
const newAudioTrack = audioTracks.find((t) => t.language == 'es');
goog.asserts.assert(newAudioTrack, 'audio track must be non-null');
player.selectAudioTrack(newAudioTrack);
expect(getActiveTextTrack().id).toBe(newTextTrack.id);
});
// https://github.com/shaka-project/shaka-player/issues/3262
it('selectAudioLanguage() doesn\'t change resolution', () => {
it('selectAudioTrack() doesn\'t change resolution', () => {
player.configure('abr.enabled', false);
abrManager.chooseIndex = 1;
const lowResEn =
@@ -2638,33 +2556,39 @@ describe('Player', () => {
// Switching to 'es' should keep the low-res stream and not choose the
// high-res version.
player.selectAudioLanguage('es');
const newAudioTrack = audioTracks.find((t) => t.language == 'es');
goog.asserts.assert(newAudioTrack, 'audio track must be non-null');
player.selectAudioTrack(newAudioTrack);
const lowResEs =
variantTracks.filter((t) => t.language == 'es' && t.height == 200)[0];
expect(getActiveVariantTrack().id).toBe(lowResEs.id);
});
it('selectTextLanguage() does not change selected variant track', () => {
it('selectTextTrack() does not change selected variant track', () => {
// This came up in a custom application that allows to select
// from all tracks regardless of selected language.
// We imitate this behavior by calling selectAudioLanguage()
// We imitate this behavior by calling selectAudioTrack()
// with one language and then selecting a track in a different
// language.
player.selectAudioLanguage('es');
const newAudioTrack = audioTracks.find((t) => t.language == 'es');
goog.asserts.assert(newAudioTrack, 'audio track must be non-null');
player.selectAudioTrack(newAudioTrack);
const englishVariantTrack =
variantTracks.filter((t) => t.language == 'en')[0];
player.selectVariantTrack(englishVariantTrack);
player.selectTextLanguage('es');
const newTextTrack = textTracks.find((t) => t.language == 'es');
player.selectTextTrack(newTextTrack);
expect(getActiveVariantTrack().id).toBe(englishVariantTrack.id);
});
it('selectTextLanguage() takes precedence over ' +
it('selectTextTrack() takes precedence over ' +
'preferredTextLanguage', () => {
// This preference is set in beforeEach, before load().
expect(player.getConfiguration().preferredTextLanguage).toBe('es');
expect(getActiveTextTrack().language).toBe('es');
player.selectTextLanguage('en');
const newTextTrack = textTracks.find((t) => t.language == 'en');
player.selectTextTrack(newTextTrack);
expect(streamingEngine.switchTextStream).toHaveBeenCalled();
const args = streamingEngine.switchTextStream.calls.argsFor(0);
@@ -2672,10 +2596,12 @@ describe('Player', () => {
expect(getActiveTextTrack().language).toBe('en');
});
it('selectTextLanguage() respects selected role', () => {
it('selectTextTrack() respects selected role', () => {
expect(getActiveTextTrack().roles).not.toContain('commentary');
player.selectTextLanguage('en', 'commentary');
const newTextTrack = textTracks.find((t) =>
t.language == 'en' && t.roles.includes('commentary'));
player.selectTextTrack(newTextTrack);
expect(streamingEngine.switchTextStream).toHaveBeenCalled();
const args = streamingEngine.switchTextStream.calls.argsFor(0);
@@ -2686,7 +2612,9 @@ describe('Player', () => {
it('changing current audio language changes active stream', () => {
expect(getActiveVariantTrack().language).not.toBe('es');
expect(streamingEngine.switchVariant).not.toHaveBeenCalled();
player.selectAudioLanguage('es');
const newAudioTrack = audioTracks.find((t) => t.language == 'es');
goog.asserts.assert(newAudioTrack, 'audio track must be non-null');
player.selectAudioTrack(newAudioTrack);
expect(streamingEngine.switchVariant).toHaveBeenCalled();
const args = streamingEngine.switchVariant.calls.argsFor(0);
@@ -2698,7 +2626,8 @@ describe('Player', () => {
it('changing current text language changes active stream', () => {
expect(getActiveTextTrack().language).not.toBe('en');
expect(streamingEngine.switchTextStream).not.toHaveBeenCalled();
player.selectTextLanguage('en');
const newTextTrack = textTracks.find((t) => t.language == 'en');
player.selectTextTrack(newTextTrack);
expect(streamingEngine.switchTextStream).toHaveBeenCalled();
const args = streamingEngine.switchTextStream.calls.argsFor(0);
@@ -2706,19 +2635,6 @@ describe('Player', () => {
expect(getActiveTextTrack().language).toBe('en');
});
// https://github.com/shaka-project/shaka-player/issues/2010
it('changing text lang changes active stream when not streaming', () => {
player.setTextTrackVisibility(false);
expect(getActiveTextTrack()).toBe(null);
expect(streamingEngine.switchTextStream).not.toHaveBeenCalled();
player.selectTextLanguage('en');
player.setTextTrackVisibility(true);
expect(streamingEngine.switchTextStream).toHaveBeenCalled();
expect(getActiveTextTrack().language).toBe('en');
});
it('remembers the channel count when ABR is reenabled', () => {
// We prefer 6 channels, and we are currently playing 6 channels.
expect(player.getConfiguration().preferredAudioChannelCount).toBe(6);
@@ -2875,48 +2791,6 @@ describe('Player', () => {
expect(variantChanged).not.toHaveBeenCalled();
});
it('in selectTextLanguage', async () => {
// The current text language.
const currentLanguage = player.getTextTracks()
.filter((t) => t.active)[0].language;
const newLanguage = player.getTextTracks()
.filter((t) => t.language != currentLanguage)[0].language;
// Call selectTextLanguage with a new language. Expect an event to
// fire.
player.selectTextLanguage(newLanguage);
await shaka.test.Util.shortDelay();
expect(textChanged).toHaveBeenCalled();
textChanged.calls.reset();
// Call again with the same language, and expect no event to fire,
// since nothing changed this time.
player.selectTextLanguage(newLanguage);
await shaka.test.Util.shortDelay();
expect(textChanged).not.toHaveBeenCalled();
});
it('in selectAudioLanguage', async () => {
// The current audio language.
const currentLanguage = player.getVariantTracks()
.filter((t) => t.active)[0].language;
const newLanguage = player.getVariantTracks()
.filter((t) => t.language != currentLanguage)[0].language;
// Call selectAudioLanguage with a new language. Expect an event to
// fire.
player.selectAudioLanguage(newLanguage);
await shaka.test.Util.shortDelay();
expect(variantChanged).toHaveBeenCalled();
variantChanged.calls.reset();
// Call again with the same language, and expect no event to fire,
// since nothing changed this time.
player.selectAudioLanguage(newLanguage);
await shaka.test.Util.shortDelay();
expect(variantChanged).not.toHaveBeenCalled();
});
it('in selectAudioTrack', async () => {
// New audio track.
const newAudioTrack = player.getAudioTracks().find((t) => !t.active);
@@ -2946,8 +2820,6 @@ describe('Player', () => {
await player.load(fakeManifestUri, 0, fakeMimeType);
// Text was turned on during startup.
expect(player.isTextTrackVisible()).toBe(true);
expect(getActiveTextTrack()).toEqual(jasmine.objectContaining({
id: 52,
language: 'en',
@@ -2993,48 +2865,6 @@ describe('Player', () => {
await runTest(['en', 'es', 'pt-BR'], 'pt-PT', 2);
});
it('enables text if its language differs from audio at start', async () => {
// A manifest we can use to test text visibility.
manifest = shaka.test.ManifestGenerator.generate((manifest) => {
manifest.addVariant(0, (variant) => {
variant.language = 'pt';
variant.addAudio(0);
});
manifest.addVariant(1, (variant) => {
variant.language = 'en';
variant.addAudio(1);
});
manifest.addTextStream(2, (stream) => {
stream.language = 'pt';
});
manifest.addTextStream(3, (stream) => {
stream.language = 'fr';
});
});
player.configure({
preferredAudioLanguage: 'en',
preferredTextLanguage: 'fr',
});
expect(player.isTextTrackVisible()).toBe(false);
await player.load(fakeManifestUri, 0, fakeMimeType);
// Text was turned on during startup.
expect(player.isTextTrackVisible()).toBe(true);
// Turn text back off.
await player.setTextTrackVisibility(false);
expect(player.isTextTrackVisible()).toBe(false);
// Change text languages after startup.
player.selectTextLanguage('pt');
// This should not turn text back on.
expect(player.isTextTrackVisible()).toBe(false);
});
it('chooses an arbitrary language when none given', async () => {
// The Player shouldn't allow changing between languages, so it should
// choose an arbitrary language when none is given.
@@ -4531,18 +4361,6 @@ describe('Player', () => {
abrManager.switchCallback(manifest.variants[2]);
});
describe('isTextTrackVisible', () => {
it('does not throw before load', () => {
player.isTextTrackVisible();
});
});
describe('setTextTrackVisibility', () => {
it('does not throw before load', async () => {
await player.setTextTrackVisibility(true);
});
});
describe('isAudioOnly', () => {
it('detects audio-only content', async () => {
// False before we've loaded anything.
@@ -4697,8 +4515,6 @@ describe('Player', () => {
});
describe('language methods', () => {
let videoOnlyManifest;
beforeEach(() => {
manifest = shaka.test.ManifestGenerator.generate((manifest) => {
manifest.addVariant(1, (variant) => {
@@ -4753,125 +4569,6 @@ describe('Player', () => {
stream.roles = ['main', 'subtitle'];
});
});
videoOnlyManifest = shaka.test.ManifestGenerator.generate((manifest) => {
manifest.addVariant(1, (variant) => {
variant.bandwidth = 400;
variant.addVideo(1);
});
manifest.addVariant(2, (variant) => {
variant.bandwidth = 800;
variant.addVideo(2);
});
});
});
describe('get*Languages', () => {
it('returns a list of languages', async () => {
await player.load(fakeManifestUri, 0, fakeMimeType);
expect(player.getAudioLanguages()).toEqual(['fr', 'en', 'de']);
expect(player.getTextLanguages()).toEqual(['es', 'en']);
});
it('returns "und" for video-only tracks', async () => {
manifest = videoOnlyManifest;
await player.load(fakeManifestUri, 0, fakeMimeType);
expect(player.getAudioLanguages()).toEqual(['und']);
expect(player.getTextLanguages()).toEqual([]);
});
});
describe('getAudioLanguagesAndRoles', () => {
it('ignores video roles and labels', async () => {
manifest = shaka.test.ManifestGenerator.generate((manifest) => {
manifest.addVariant(0, (variant) => {
variant.language = 'en';
variant.addVideo(1, (stream) => {
stream.roles = ['video-only-role'];
stream.label = 'should not show up';
});
variant.addAudio(2, (stream) => {
stream.roles = ['audio-only-role'];
stream.language = 'en';
});
});
});
await player.load(fakeManifestUri, 0, fakeMimeType);
expect(player.getAudioLanguagesAndRoles()).toEqual([
{language: 'en', role: 'audio-only-role', label: null},
]);
});
it('lists all language-role combinations', async () => {
await player.load(fakeManifestUri, 0, fakeMimeType);
expect(player.getAudioLanguagesAndRoles()).toEqual([
{language: 'fr', role: '', label: null},
{language: 'en', role: 'main', label: null},
{language: 'en', role: 'commentary', label: null},
{language: 'de', role: 'foo', label: null},
{language: 'de', role: 'bar', label: null},
]);
});
it('associates audio streams with their labels', async () => {
manifest = shaka.test.ManifestGenerator.generate((manifest) => {
manifest.addVariant(0, (variant) => {
variant.language = 'en';
variant.addAudio(1, (stream) => {
stream.roles = ['role-1'];
stream.language = 'en';
stream.label = 'english';
});
});
manifest.addVariant(0, (variant) => {
variant.language = 'es';
variant.addAudio(2, (stream) => {
stream.roles = ['role-2', 'role-3'];
stream.language = 'es';
stream.label = 'spanish';
});
});
});
await player.load(fakeManifestUri, 0, fakeMimeType);
expect(player.getAudioLanguagesAndRoles()).toEqual([
{language: 'en', role: 'role-1', label: 'english'},
{language: 'es', role: 'role-2', label: 'spanish'},
{language: 'es', role: 'role-3', label: 'spanish'},
]);
});
it('uses "und" for video-only tracks', async () => {
manifest = shaka.test.ManifestGenerator.generate((manifest) => {
manifest.addVariant(0, (variant) => {
variant.addVideo(1, (stream) => {
stream.roles = ['video-only-role'];
});
});
});
await player.load(fakeManifestUri, 0, fakeMimeType);
expect(player.getAudioLanguagesAndRoles()).toEqual([
{language: 'und', role: '', label: null},
]);
});
});
describe('getTextLanguageAndRoles', () => {
it('lists all language-role combinations', async () => {
await player.load(fakeManifestUri, 0, fakeMimeType);
expect(player.getTextLanguagesAndRoles()).toEqual([
{language: 'es', role: 'baz', label: null},
{language: 'es', role: 'qwerty', label: null},
{language: 'en', role: 'main', label: null},
{language: 'en', role: 'caption', label: null},
{language: 'en', role: 'subtitle', label: null},
]);
});
});
describe('getThumbnails', () => {
-5
View File
@@ -64,11 +64,6 @@ shaka.test.FakeAdManager = class extends shaka.util.FakeEventTarget {
/** @override */
replaceServerSideAdTagParameters(adTagParameters) {}
/** @override */
getServerSideCuePoints() {
return [];
}
/** @override */
getCuePoints() {
return [];
+8 -6
View File
@@ -348,13 +348,15 @@ shaka.test.NativeTextLayoutTests = class extends shaka.test.TextLayoutTests {
getMediaElement: () => this.video,
getLoadMode: () => shaka.Player.LoadMode.MEDIA_SOURCE,
getTextTracks: () => textTracks,
selectTextTrack: ({id}) => {
const track = textTracks.find((t) => t.id === id);
expect(track).toBeTruthy();
track.active = true;
selectTextTrack: (track) => {
if (track) {
const activeTrack = textTracks.find((t) => t.id === track.id);
expect(activeTrack).toBeTruthy();
this.textDisplayer.setTextVisibility(true);
} else {
this.textDisplayer.setTextVisibility(false);
}
},
setTextTrackVisibility: (visible) =>
this.textDisplayer.setTextVisibility(visible),
};
this.video = shaka.test.UiUtils.createVideoElement();
+9
View File
@@ -44,6 +44,9 @@ shaka.test.FakeAbrManager = class {
/** @type {!jasmine.Spy} */
this.disable = jasmine.createSpy('disable');
/** @type {!jasmine.Spy} */
this.trySuggestStreams = jasmine.createSpy('trySuggestStreams');
/** @type {!jasmine.Spy} */
this.segmentDownloaded = jasmine.createSpy('segmentDownloaded');
@@ -63,6 +66,12 @@ shaka.test.FakeAbrManager = class {
/** @type {!jasmine.Spy} */
this.playbackRateChanged = jasmine.createSpy('playbackRateChanged');
/** @type {!jasmine.Spy} */
this.setMediaElement = jasmine.createSpy('setMediaElement');
/** @type {!jasmine.Spy} */
this.setCmsdManager = jasmine.createSpy('setCmsdManager');
/** @type {!jasmine.Spy} */
this.configure = jasmine.createSpy('configure');
}
-2
View File
@@ -35,8 +35,6 @@ describe('NativeTextDisplayer', () => {
expect(track).toBeTruthy();
track.active = true;
},
setTextTrackVisibility: (visible) =>
displayer.setTextVisibility(visible),
};
video = new shaka.test.FakeVideo();
/** @suppress {checkTypes} */
-469
View File
@@ -1,469 +0,0 @@
/*! @license
* Shaka Player
* Copyright 2016 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
describe('SimpleTextDisplayer', () => {
const originalVTTCue = window.VTTCue;
const Cue = shaka.text.Cue;
const SimpleTextDisplayer = shaka.text.SimpleTextDisplayer;
/** @type {!shaka.test.FakeVideo} */
let video;
/** @type {!shaka.test.FakeTextTrack} */
let mockTrack;
/** @type {!shaka.text.SimpleTextDisplayer} */
let displayer;
beforeEach(() => {
video = new shaka.test.FakeVideo();
displayer = new SimpleTextDisplayer(video, shaka.Player.TextTrackLabel);
displayer.enableTextDisplayer();
expect(video.textTracks.length).toBe(1);
mockTrack = /** @type {!shaka.test.FakeTextTrack} */ (video.textTracks[0]);
expect(mockTrack).toBeTruthy();
/**
* @constructor
* @param {number} start
* @param {number} end
* @param {string} text
*/
function FakeVTTCue(start, end, text) {
this.startTime = start;
this.endTime = end;
this.text = text;
this.snapToLines = true;
this.vertical = undefined;
this.line = 'auto';
this.position = 'auto';
}
window.VTTCue = /** @type {?} */(FakeVTTCue);
});
afterEach(async () => {
await displayer.destroy();
});
afterAll(() => {
window.VTTCue = originalVTTCue;
});
describe('append', () => {
it('sorts cues before inserting', () => {
// See: https://bit.ly/2K9VX3s
verifyHelper(
[
{startTime: 10, endTime: 20, text: 'Test1'},
{startTime: 20, endTime: 30, text: 'Test2'},
{startTime: 30, endTime: 40, text: 'Test3'},
],
[
new shaka.text.Cue(20, 30, 'Test2'),
new shaka.text.Cue(30, 40, 'Test3'),
new shaka.text.Cue(10, 20, 'Test1'),
]);
});
it('appends equal time cues in reverse order', () => {
// Regression test for https://github.com/shaka-project/shaka-player/issues/848
// When VTTCue is seen as the real thing (because of the presence of
// VTTCue.prototype.line), then the reverse-order behavior comes into
// play. The reverse order is only needed because of VTTCue spec
// behavior.
// First we test the behavior with a real-looking VTTCue (in which
// prototype.line merely exists). This simulates Chrome, Firefox, and
// Safari.
// eslint-disable-next-line no-restricted-syntax
window.VTTCue.prototype['line'] = 'auto';
verifyHelper(
[
{startTime: 20, endTime: 40, text: 'Test1'},
{startTime: 20, endTime: 40, text: 'Test2'},
{startTime: 20, endTime: 40, text: 'Test3'},
],
[
// Reverse order to compensate for the way line='auto' is
// implemented in browsers.
new shaka.text.Cue(20, 40, 'Test3'),
new shaka.text.Cue(20, 40, 'Test2'),
new shaka.text.Cue(20, 40, 'Test1'),
]);
// Next we test the behavior with a VTTCue which is seen as a cheap
// polyfill (in which prototype.line does not exist). This simulates
// legacy Edge.
// eslint-disable-next-line no-restricted-syntax
delete window.VTTCue.prototype['line'];
displayer.remove(0, Infinity); // Clear the cues from above.
verifyHelper(
[
{startTime: 20, endTime: 40, text: 'Test1'},
{startTime: 20, endTime: 40, text: 'Test2'},
{startTime: 20, endTime: 40, text: 'Test3'},
],
[
// Input order, since the displayer sees this as a fake VTTCue
// implementation.
new shaka.text.Cue(20, 40, 'Test1'),
new shaka.text.Cue(20, 40, 'Test2'),
new shaka.text.Cue(20, 40, 'Test3'),
]);
});
it('appends nested cues', () => {
const shakaCue = new shaka.text.Cue(10, 20, '');
const nestedCue1 = new shaka.text.Cue(10, 20, 'Test1 ');
const nestedCue2 = new shaka.text.Cue(10, 20, 'Test2');
shakaCue.nestedCues = [nestedCue1, nestedCue2];
verifyHelper(
[
{startTime: 10, endTime: 20, text: 'Test1 Test2'},
],
[shakaCue]);
});
it('flattens nested cue payloads correctly', () => {
const level0ContainerCue = new shaka.text.Cue(10, 30, '');
level0ContainerCue.isContainer = true;
const level1NonContainerCueA = new shaka.text.Cue(10, 20, '');
const level1NonContainerCueB = new shaka.text.Cue(20, 30, '');
// Add a trailing whitespace character to get a space-delimited expected
// result.
const cueANestedCue0 = new shaka.text.Cue(10, 20, 'Cue A Test0 ');
const cueANestedCue1 = new shaka.text.Cue(10, 20, 'Cue A Test1');
const cueBNestedCue0 = new shaka.text.Cue(20, 30, 'Cue B Test0 ');
const cueBNestedCue1 = new shaka.text.Cue(20, 30, 'Cue B Test1');
level1NonContainerCueA.nestedCues = [cueANestedCue0, cueANestedCue1];
level1NonContainerCueB.nestedCues = [cueBNestedCue0, cueBNestedCue1];
level0ContainerCue.nestedCues =
[level1NonContainerCueA, level1NonContainerCueB];
verifyHelper(
[
{startTime: 10, endTime: 20, text: 'Cue A Test0 Cue A Test1'},
{startTime: 20, endTime: 30, text: 'Cue B Test0 Cue B Test1'},
],
[level0ContainerCue]);
});
// Regression test for b/159050711
it('maintains the styles of the parent cue', () => {
const shakaCue = new shaka.text.Cue(10, 20, '');
const nestedCue1 = new shaka.text.Cue(10, 20, 'Test1 ');
const nestedCue2 = new shaka.text.Cue(10, 20, 'Test2');
shakaCue.nestedCues = [nestedCue1, nestedCue2];
shakaCue.lineAlign = Cue.lineAlign.CENTER;
nestedCue1.lineAlign = Cue.lineAlign.START;
nestedCue2.lineAlign = Cue.lineAlign.START;
verifyHelper(
[
{
startTime: 10,
endTime: 20,
text: 'Test1 Test2',
lineAlign: 'center',
},
],
[shakaCue]);
});
it('creates style tags for cues with underline/italics/bold', () => {
const shakaCue = new shaka.text.Cue(10, 20, '');
// First cue is underlined and italicized.
const nestedCue1 = new shaka.text.Cue(10, 20, 'Test1');
nestedCue1.fontStyle = shaka.text.Cue.fontStyle.ITALIC;
nestedCue1.textDecoration.push(shaka.text.Cue.textDecoration.UNDERLINE);
// Second cue is italicized and bolded.
const nestedCue2 = new shaka.text.Cue(10, 20, 'Test2');
nestedCue2.fontStyle = shaka.text.Cue.fontStyle.ITALIC;
nestedCue2.fontWeight = shaka.text.Cue.fontWeight.BOLD;
// Third cue has no bold, italics, or underline.
const nestedCue3 = new shaka.text.Cue(10, 20, 'Test3');
// Fourth cue is only underlined.
const nestedCue4 = new shaka.text.Cue(10, 20, 'Test4');
nestedCue4.textDecoration.push(shaka.text.Cue.textDecoration.UNDERLINE);
const expectedText =
'<i><u>Test1</u></i><b><i>Test2</i></b>Test3<u>Test4</u>';
shakaCue.nestedCues = [nestedCue1, nestedCue2, nestedCue3, nestedCue4];
verifyHelper(
[
{startTime: 10, endTime: 20, text: expectedText},
],
[shakaCue]);
});
it('adds linebreaks when a linebreak cue is seen', () => {
const shakaCue = new shaka.text.Cue(10, 20, '');
const nestedCue1 = new shaka.text.Cue(10, 20, 'Test1');
// Second cue is a linebreak cue.
const nestedCue2 = new shaka.text.Cue(10, 20, '');
nestedCue2.lineBreak = true;
const nestedCue3 = new shaka.text.Cue(10, 20, 'Test2');
shakaCue.nestedCues = [nestedCue1, nestedCue2, nestedCue3];
verifyHelper(
[
{startTime: 10, endTime: 20, text: 'Test1\nTest2'},
],
[shakaCue]);
});
it('skips duplicate cues', () => {
const cue1 = new shaka.text.Cue(10, 20, 'Test');
displayer.append([cue1]);
expect(mockTrack.addCue).toHaveBeenCalledTimes(1);
mockTrack.addCue.calls.reset();
const cue2 = new shaka.text.Cue(10, 20, 'Test');
displayer.append([cue2]);
expect(mockTrack.addCue).not.toHaveBeenCalled();
});
});
describe('remove', () => {
it('removes cues which overlap the range', () => {
const cue1 = new shaka.text.Cue(0, 1, 'Test');
const cue2 = new shaka.text.Cue(1, 2, 'Test');
const cue3 = new shaka.text.Cue(2, 3, 'Test');
displayer.append([cue1, cue2, cue3]);
displayer.remove(0, 1);
expect(mockTrack.removeCue).toHaveBeenCalledTimes(1);
expect(mockTrack.removeCue).toHaveBeenCalledWith(
jasmine.objectContaining({startTime: 0, endTime: 1}));
mockTrack.removeCue.calls.reset();
displayer.remove(0.5, 1.001);
expect(mockTrack.removeCue).toHaveBeenCalledTimes(1);
expect(mockTrack.removeCue).toHaveBeenCalledWith(
jasmine.objectContaining({startTime: 1, endTime: 2}));
mockTrack.removeCue.calls.reset();
displayer.remove(3, 5);
expect(mockTrack.removeCue).not.toHaveBeenCalled();
mockTrack.removeCue.calls.reset();
displayer.remove(2.9999, Infinity);
expect(mockTrack.removeCue).toHaveBeenCalledTimes(1);
expect(mockTrack.removeCue).toHaveBeenCalledWith(
jasmine.objectContaining({startTime: 2, endTime: 3}));
mockTrack.removeCue.calls.reset();
});
it('does nothing when nothing is buffered', () => {
displayer.remove(0, 1);
expect(mockTrack.removeCue).not.toHaveBeenCalled();
});
});
describe('convertToTextTrackCue', () => {
it('converts shaka.text.Cues to VttCues', () => {
verifyHelper(
[
{startTime: 20, endTime: 40, text: 'Test4'},
],
[
new shaka.text.Cue(20, 40, 'Test4'),
]);
const cue1 = new shaka.text.Cue(20, 40, 'Test5');
cue1.positionAlign = Cue.positionAlign.LEFT;
cue1.lineAlign = Cue.lineAlign.START;
cue1.size = 80;
cue1.textAlign = Cue.textAlign.LEFT;
cue1.writingMode = Cue.writingMode.VERTICAL_LEFT_TO_RIGHT;
cue1.lineInterpretation = Cue.lineInterpretation.LINE_NUMBER;
cue1.line = 5;
cue1.position = 10;
verifyHelper(
[
{
startTime: 20,
endTime: 40,
text: 'Test5',
lineAlign: 'start',
positionAlign: 'line-left',
size: 80,
align: 'left',
vertical: 'lr',
snapToLines: true,
line: 5,
position: 10,
},
], [cue1]);
const cue2 = new shaka.text.Cue(30, 50, 'Test');
cue2.positionAlign = Cue.positionAlign.RIGHT;
cue2.lineAlign = Cue.lineAlign.END;
cue2.textAlign = Cue.textAlign.RIGHT;
cue2.writingMode = Cue.writingMode.VERTICAL_RIGHT_TO_LEFT;
cue2.lineInterpretation = Cue.lineInterpretation.PERCENTAGE;
cue2.line = 5;
verifyHelper(
[
{
startTime: 30,
endTime: 50,
text: 'Test',
lineAlign: 'end',
positionAlign: 'line-right',
align: 'right',
vertical: 'rl',
snapToLines: false,
line: 5,
},
], [cue2]);
const cue3 = new shaka.text.Cue(40, 60, 'Test1');
cue3.positionAlign = Cue.positionAlign.CENTER;
cue3.lineAlign = Cue.lineAlign.CENTER;
cue3.textAlign = Cue.textAlign.START;
cue3.direction = Cue.direction.HORIZONTAL_LEFT_TO_RIGHT;
verifyHelper(
[
{
startTime: 40,
endTime: 60,
text: 'Test1',
lineAlign: 'center',
positionAlign: 'center',
align: 'start',
vertical: undefined,
},
], [cue3]);
const cue4 = new shaka.text.Cue(40, 60, 'Test2');
cue4.line = null;
cue4.position = null;
verifyHelper(
[
{
startTime: 40,
endTime: 60,
text: 'Test2',
line: 'auto',
position: 'auto',
},
], [cue4]);
const cue5 = new shaka.text.Cue(40, 60, 'Test3');
cue5.line = 0;
cue5.position = 0;
verifyHelper(
[
{
startTime: 40,
endTime: 60,
text: 'Test3',
line: 0,
position: 0,
},
], [cue5]);
});
it('works around browsers not supporting align=center', () => {
/**
* @constructor
* @param {number} start
* @param {number} end
* @param {string} text
*/
function FakeVTTCueWithoutAlignCenter(start, end, text) {
let align = 'middle';
Object.defineProperty(this, 'align', {
get: () => align,
set: (newValue) => {
if (newValue != 'center') {
align = newValue;
}
},
});
this.startTime = start;
this.endTime = end;
this.text = text;
}
window.VTTCue = /** @type {?} */(FakeVTTCueWithoutAlignCenter);
const cue1 = new shaka.text.Cue(20, 40, 'Test');
cue1.textAlign = Cue.textAlign.CENTER;
verifyHelper(
[
{
startTime: 20,
endTime: 40,
text: 'Test',
align: 'middle',
},
],
[cue1]);
});
it('ignores cues with startTime >= endTime', () => {
mockTrack.addCue.calls.reset();
const cue1 = new shaka.text.Cue(60, 40, 'Test');
const cue2 = new shaka.text.Cue(40, 40, 'Test');
displayer.append([cue1, cue2]);
expect(mockTrack.addCue).not.toHaveBeenCalled();
});
});
describe('destroy', () => {
it('disables the TextTrack it created', async () => {
// There should only be the one track created by this displayer.
expect(video.textTracks.length).toBe(1);
/** @type {!TextTrack} */
const textTrack = video.textTracks[0];
// It should not be disabled before we destroy it.
expect(textTrack.mode).not.toBe('disabled');
await displayer.destroy();
// It should be disabled after we destroy it.
expect(textTrack.mode).toBe('disabled');
});
});
function createFakeCue(startTime, endTime) {
return {startTime: startTime, endTime: endTime};
}
/**
* Verifies that vttCues are converted to shakaCues and appended.
* @param {!Array} vttCues
* @param {!Array<!shaka.text.Cue>} shakaCues
*/
function verifyHelper(vttCues, shakaCues) {
mockTrack.addCue.calls.reset();
displayer.append(shakaCues);
const result = mockTrack.addCue.calls.allArgs().reduce(
shaka.util.Functional.collapseArrays, []);
expect(result).toEqual(vttCues.map((c) => jasmine.objectContaining(c)));
}
});
+5
View File
@@ -22,6 +22,9 @@ describe('TextEngine', () => {
/** @type {!jasmine.Spy} */
let mockSetSequenceMode;
/** @type {!jasmine.Spy} */
let mockSetManifestType;
/** @type {!jasmine.Spy} */
let mockParseMedia;
@@ -31,12 +34,14 @@ describe('TextEngine', () => {
beforeEach(() => {
mockParseInit = jasmine.createSpy('mockParseInit');
mockSetSequenceMode = jasmine.createSpy('mockSetSequenceMode');
mockSetManifestType = jasmine.createSpy('mockSetManifestType');
mockParseMedia = jasmine.createSpy('mockParseMedia');
// eslint-disable-next-line no-restricted-syntax
mockParserPlugIn = function() {
return {
parseInit: mockParseInit,
setSequenceMode: mockSetSequenceMode,
setManifestType: mockSetManifestType,
parseMedia: mockParseMedia,
};
};
+59 -24
View File
@@ -147,7 +147,10 @@ describe('UI', () => {
newLanguage = 'es';
languageMenu = shaka.util.Dom.getElementByClassName(
'shaka-audio-languages', videoContainer);
setupLanguageTests(player.getAudioLanguagesAndRoles());
const audioTracks = player.getAudioTracks();
const uniqueLanguages =
[...new Set(audioTracks.map((track) => track.language))];
setupLanguageTests(uniqueLanguages);
});
it('contains all the languages', () => {
@@ -160,10 +163,18 @@ describe('UI', () => {
});
it('choosing language through API has effect on UI', async () => {
const selectAudioLanguage = (language) => {
const audioTracks = player.getAudioTracks();
const track = audioTracks.find((t) => t.language == language);
if (track) {
player.selectAudioTrack(track);
}
};
await verifyLanguageChangeViaAPI(
'languageselectionupdated',
() => player.getVariantTracks(),
(language) => player.selectAudioLanguage(language));
(language) => selectAudioLanguage(language));
});
}); // describe('audio')
@@ -173,7 +184,10 @@ describe('UI', () => {
newLanguage = 'fr';
languageMenu = shaka.util.Dom.getElementByClassName(
'shaka-text-languages', videoContainer);
setupLanguageTests(player.getTextLanguagesAndRoles());
const textTracks = player.getTextTracks();
const uniqueLanguages =
[...new Set(textTracks.map((track) => track.language))];
setupLanguageTests(uniqueLanguages);
});
it('contains all the languages', () => {
@@ -189,39 +203,58 @@ describe('UI', () => {
it('choosing language through API has effect on UI', async () => {
// Enable & verify the text, or else the text won't be streamed and the
// language selection won't do anything.
await player.setTextTrackVisibility(true);
expect(player.isTextTrackVisible()).toBe(true);
let textTracks = player.getTextTracks();
player.selectTextTrack(textTracks[0]);
textTracks = player.getTextTracks();
const activeTrack = textTracks.find((t) => t.active);
expect(activeTrack).toBeDefined();
const selectTextLanguage = (language) => {
const textTracks = player.getTextTracks();
const track = textTracks.find((t) => t.language == language);
if (track) {
player.selectTextTrack(track);
}
};
await verifyLanguageChangeViaAPI(
'captionselectionupdated',
() => player.getTextTracks(),
(language) => player.selectTextLanguage(language));
(language) => selectTextLanguage(language));
});
it('turning captions off through UI has effect on player', async () => {
// Enable & verify the text.
await player.setTextTrackVisibility(true);
expect(player.isTextTrackVisible()).toBe(true);
let textTracks = player.getTextTracks();
player.selectTextTrack(textTracks[0]);
textTracks = player.getTextTracks();
let activeTrack = textTracks.find((t) => t.active);
expect(activeTrack).toBeDefined();
// Find and click the 'Off' button
getOffButton().click();
// Wait for the change to take effect
await waiter.waitForEvent(player, 'texttrackvisibility');
await waiter.waitForEvent(player, 'textchanged');
expect(player.isTextTrackVisible()).toBe(false);
textTracks = player.getTextTracks();
activeTrack = textTracks.find((t) => t.active);
expect(activeTrack).toBeUndefined();
});
it('turning captions off through API has effect on UI', async () => {
// This test is invalid if the text is not initially visible, because
// setTextTrackVisibility() does nothing if there are no changes.
await player.setTextTrackVisibility(true);
expect(player.isTextTrackVisible()).toBe(true);
// This test is invalid if the text is not initially visible.
let textTracks = player.getTextTracks();
player.selectTextTrack(textTracks[0]);
textTracks = player.getTextTracks();
let activeTrack = textTracks.find((t) => t.active);
expect(activeTrack).toBeDefined();
const p = waiter.waitForEvent(controls, 'captionselectionupdated');
// Disable & verify the text.
await player.setTextTrackVisibility(false);
expect(player.isTextTrackVisible()).toBe(false);
player.selectTextTrack();
textTracks = player.getTextTracks();
activeTrack = textTracks.find((t) => t.active);
expect(activeTrack).toBeUndefined();
// Wait for the change to take effect
await p;
@@ -244,12 +277,10 @@ describe('UI', () => {
}); // describe('caption selection')
/**
* @param {!Array<shaka.extern.LanguageRole>} languagesAndRoles
* @param {!Array<string>} langs
*/
function setupLanguageTests(languagesAndRoles) {
langsFromContent = languagesAndRoles.map((langAndRole) => {
return langAndRole.language;
});
function setupLanguageTests(langs) {
langsFromContent = langs;
languageButtons = filterButtons(languageMenu.childNodes,
['shaka-back-to-overflow-button', 'shaka-turn-captions-off-button']);
@@ -360,8 +391,12 @@ describe('UI', () => {
const selectedLanguage =
getSelectedTrack(player.getVariantTracks()).language;
if (selectedLanguage != preferredLanguage) {
player.selectAudioLanguage(preferredLanguage);
await waiter.waitForEvent(player, 'variantchanged');
const audioTracks = player.getAudioTracks();
const track = audioTracks.find((t) => t.language == preferredLanguage);
if (track) {
player.selectAudioTrack(track);
await waiter.waitForEvent(player, 'variantchanged');
}
}
resolutionsMenu = shaka.util.Dom.getElementByClassName(
-25
View File
@@ -527,31 +527,6 @@ describe('tXml', () => {
]);
});
it('txmlNodeToDomElement', () => {
const node = {
tagName: 'Event',
parent: null,
attributes: {
'presentationTime': '0',
},
children: [
{
tagName: 'scte35:Signal',
parent: null,
attributes: {},
children: [],
},
],
};
node.children[0].parent = node;
const element = TXml.txmlNodeToDomElement(node);
expect(element.tagName).toBe('Event');
expect(element.getAttribute('presentationTime')).toBe('0');
const signal = element.firstElementChild;
expect(signal.tagName).toBe('scte35:Signal');
});
it('cloneNode', () => {
expect(TXml.cloneNode(null)).toBe(null);
const root = {
+1 -1
View File
@@ -2028,7 +2028,7 @@ shaka.ui.Controls = class extends shaka.util.FakeEventTarget {
const tracks = this.player_.getTextTracks();
const hasTrack = tracks.some((track) => track.active);
if (hasTrack) {
this.player_.selectTextTrack(null);
this.player_.selectTextTrack();
} else {
this.player_.selectTextTrack(this.lastSelectedTextTrack_);
}
+1 -1
View File
@@ -158,7 +158,7 @@ shaka.ui.TextSelection = class extends shaka.ui.SettingsMenu {
const offButton = shaka.util.Dom.createButton();
offButton.classList.add('shaka-turn-captions-off-button');
this.eventManager.listen(offButton, 'click', () => {
this.player.selectTextTrack(null);
this.player.selectTextTrack();
});
offButton.appendChild(this.captionsOffSpan_);