diff --git a/build/types/core b/build/types/core index 8a089c0c5..5ec800009 100644 --- a/build/types/core +++ b/build/types/core @@ -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 diff --git a/docs/tutorials/manifest-parser.md b/docs/tutorials/manifest-parser.md index 8d8f70974..eb2365711 100644 --- a/docs/tutorials/manifest-parser.md +++ b/docs/tutorials/manifest-parser.md @@ -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. diff --git a/externs/shaka/ads.js b/externs/shaka/ads.js index 478b29f0b..b357ddb7e 100644 --- a/externs/shaka/ads.js +++ b/externs/shaka/ads.js @@ -317,11 +317,6 @@ shaka.extern.IAdManager = class extends EventTarget { */ replaceServerSideAdTagParameters(adTagParameters) {} - /** - * @return {!Array} - */ - getServerSideCuePoints() {} - /** * @return {!Array} */ diff --git a/externs/shaka/player.js b/externs/shaka/player.js index 4ca886444..587b000bd 100644 --- a/externs/shaka/player.js +++ b/externs/shaka/player.js @@ -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 - * DEPRECATED: 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, - * manifestPreprocessor: function(!Element), * manifestPreprocessorTXml: function(!shaka.extern.xml.Node), * sequenceMode: boolean, * useStreamOnceInPeriodFlattening: boolean, @@ -1459,11 +1454,6 @@ shaka.extern.xml.Node; * @property {Object} keySystemsByURI * A map of scheme URI to key system name. Defaults to default key systems * mapping handled by Shaka. - * @property {function(!Element)} manifestPreprocessor - * DEPRECATED: 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 * }} * - * @property {function(!Element)} manifestPreprocessor - * DEPRECATED: 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 diff --git a/lib/ads/ad_manager.js b/lib/ads/ad_manager.js index 65245590a..5504d404e 100644 --- a/lib/ads/ad_manager.js +++ b/lib/ads/ad_manager.js @@ -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} - * @override - * @export - */ - getServerSideCuePoints() { - shaka.Deprecate.deprecateFeature(5, - 'AdManager.getServerSideCuePoints', - 'Please use getCuePoints function.'); - return this.getCuePoints(); - } - - /** * @return {!Array} * @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. diff --git a/lib/cast/cast_proxy.js b/lib/cast/cast_proxy.js index 8112739ea..2f20c1f1f 100644 --- a/lib/cast/cast_proxy.js +++ b/lib/cast/cast_proxy.js @@ -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 diff --git a/lib/cast/cast_receiver.js b/lib/cast/cast_receiver.js index 1c8bf8e6d..e6df93553 100644 --- a/lib/cast/cast_receiver.js +++ b/lib/cast/cast_receiver.js @@ -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']) { diff --git a/lib/cast/cast_utils.js b/lib/cast/cast_utils.js index dab14732f..c5e2a53d0 100644 --- a/lib/cast/cast_utils.js +++ b/lib/cast/cast_utils.js @@ -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>} - */ -shaka.cast.CastUtils.PlayerInitAfterLoadState = [ - ['isTextTrackVisible', 'setTextTrackVisibility'], -]; - - /** * Player methods with no return value that are proxied while casting. * @const {!Array} @@ -398,15 +383,11 @@ shaka.cast.CastUtils.PlayerVoidMethods = [ 'cancelTrickPlay', 'configure', 'configurationForLowLatency', - 'getChapters', 'resetConfiguration', 'retryStreaming', - 'selectAudioLanguage', 'selectAudioTrack', - 'selectTextLanguage', 'selectTextTrack', 'selectVariantTrack', - 'selectVariantsByLabel', 'selectVideoTrack', 'setTextTrackVisibility', 'trickPlay', diff --git a/lib/dash/dash_parser.js b/lib/dash/dash_parser.js index a727f2e2c..666fe409c 100644 --- a/lib/dash/dash_parser.js +++ b/lib/dash/dash_parser.js @@ -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), }; diff --git a/lib/dependencies/all.js b/lib/dependencies/all.js index f2c1a511c..153405dbf 100644 --- a/lib/dependencies/all.js +++ b/lib/dependencies/all.js @@ -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', }; diff --git a/lib/lcevc/lcevc_dec.js b/lib/lcevc/lcevc_dec.js index 2c606661f..a7e290f5b 100644 --- a/lib/lcevc/lcevc_dec.js +++ b/lib/lcevc/lcevc_dec.js @@ -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); } } diff --git a/lib/media/manifest_parser.js b/lib/media/manifest_parser.js index 17bca48aa..683c360ff 100644 --- a/lib/media/manifest_parser.js +++ b/lib/media/manifest_parser.js @@ -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. * diff --git a/lib/mss/mss_parser.js b/lib/mss/mss_parser.js index 4fcf71fa1..919bcc384 100644 --- a/lib/mss/mss_parser.js +++ b/lib/mss/mss_parser.js @@ -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, diff --git a/lib/player.js b/lib/player.js index c26d6be51..077fd1d14 100644 --- a/lib/player.js +++ b/lib/player.js @@ -36,7 +36,6 @@ goog.require('shaka.net.NetworkingEngine'); goog.require('shaka.net.NetworkingUtils'); goog.require('shaka.text.Cue'); goog.require('shaka.text.NativeTextDisplayer'); -goog.require('shaka.text.SimpleTextDisplayer'); goog.require('shaka.text.SpeechToText'); goog.require('shaka.text.StubTextDisplayer'); goog.require('shaka.text.TextEngine'); @@ -283,25 +282,6 @@ goog.requireType('shaka.media.PresentationTimeline'); */ -/** - * @event shaka.Player.TextTrackVisibilityEvent - * @description Fired when text track visibility changes. - * An app may want to look at getStats() or - * isTextTrackVisible() to see what happened. - * - *
- * - * This event is deprecated and will be removed in version 5.0, - * text track selection and visibility will no longer be treated - * separately. Selecting or deselecting a text track can now be - * handled entirely through `selectTextTrack`. - * @property {string} type - * 'texttrackvisibility' - * @deprecated - * @exportDoc - */ - - /** * @event shaka.Player.AudioTracksChangedEvent * @description Fired when the list of audio tracks changes. @@ -330,8 +310,8 @@ goog.requireType('shaka.media.PresentationTimeline'); * @event shaka.Player.AdaptationEvent * @description Fired when an automatic adaptation causes the active tracks * to change. Does not fire when the application calls - * selectVariantTrack(), selectTextTrack(), - * selectAudioLanguage(), or selectTextLanguage(). + * selectVariantTrack(), selectTextTrack(), or + * selectAudioTrack() * @property {string} type * 'adaptation' * @property {shaka.extern.Track} oldTrack @@ -343,9 +323,9 @@ goog.requireType('shaka.media.PresentationTimeline'); /** * @event shaka.Player.VariantChangedEvent * @description Fired when a call from the application caused a variant change. - * Can be triggered by calls to selectVariantTrack() or - * selectAudioLanguage(). Does not fire when an automatic - * adaptation causes a variant change. + * Can be triggered by calls to selectVariantTrack(), + * selectTextTrack(), or selectAudioTrack(). + * Does not fire when an automatic adaptation causes a variant change. * An app may want to look at getStats() or * getVariantTracks() to see what happened. * @property {string} type @@ -359,8 +339,7 @@ goog.requireType('shaka.media.PresentationTimeline'); /** * @event shaka.Player.TextChangedEvent * @description Fired when a call from the application caused a text stream - * change. Can be triggered by calls to selectTextTrack() or - * selectTextLanguage(). + * change. Can be triggered by calls to selectTextTrack(). * An app may want to look at getStats() or * getTextTracks() to see what happened. * @property {string} type @@ -1036,17 +1015,6 @@ shaka.Player = class extends shaka.util.FakeEventTarget { /** @private {?shaka.media.PreloadManager} */ this.preloadNextUrl_ = null; - // Even though |attach| will start in later interpreter cycles, it should be - // the LAST thing we do in the constructor because conceptually it relies on - // player having been initialized. - if (mediaElement) { - shaka.Deprecate.deprecateFeature(5, - 'Player w/ mediaElement', - 'Please migrate from initializing Player with a mediaElement; ' + - 'use the attach method instead.'); - this.attach(mediaElement, /* initializeMediaSource= */ true); - } - /** @private {?shaka.extern.TextDisplayer} */ this.textDisplayer_ = null; @@ -1918,13 +1886,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget { } if (this.manifest_ && this.manifest_.textStreams.length) { - if (this.textDisplayer_.enableTextDisplayer) { - this.textDisplayer_.enableTextDisplayer(); - } else { - shaka.Deprecate.deprecateFeature(5, - 'Text displayer w/ enableTextDisplayer', - 'Text displayer should have a "enableTextDisplayer" method!'); - } + this.textDisplayer_.enableTextDisplayer(); } // Wait for the preload manager to do all of the loading it can do. @@ -1976,24 +1938,6 @@ shaka.Player = class extends shaka.util.FakeEventTarget { this.abrManager_.release(); } this.abrManager_ = abrFactory(); - if (typeof this.abrManager_.setMediaElement != 'function') { - shaka.Deprecate.deprecateFeature(5, - 'AbrManager w/o setMediaElement', - 'Please use an AbrManager with setMediaElement function.'); - this.abrManager_.setMediaElement = () => {}; - } - if (typeof this.abrManager_.setCmsdManager != 'function') { - shaka.Deprecate.deprecateFeature(5, - 'AbrManager w/o setCmsdManager', - 'Please use an AbrManager with setCmsdManager function.'); - this.abrManager_.setCmsdManager = () => {}; - } - if (typeof this.abrManager_.trySuggestStreams != 'function') { - shaka.Deprecate.deprecateFeature(5, - 'AbrManager w/o trySuggestStreams', - 'Please use an AbrManager with trySuggestStreams function.'); - this.abrManager_.trySuggestStreams = () => {}; - } this.abrManager_.configure(this.config_.abr); } @@ -2607,18 +2551,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget { if (this.lastTextFactory_ !== textDisplayerFactory || force) { const oldDisplayer = this.textDisplayer_; this.textDisplayer_ = textDisplayerFactory(); - if (this.textDisplayer_.configure) { - this.textDisplayer_.configure(this.config_.textDisplayer); - } else { - shaka.Deprecate.deprecateFeature(5, - 'Text displayer w/ configure', - 'Text displayer should have a "configure" method!'); - } - if (!this.textDisplayer_.setTextLanguage) { - shaka.Deprecate.deprecateFeature(5, - 'Text displayer w/ setTextLanguage', - 'Text displayer should have a "setTextLanguage" method!'); - } + this.textDisplayer_.configure(this.config_.textDisplayer); if (oldDisplayer) { this.textDisplayer_.setTextVisibility(oldDisplayer.isTextVisible()); oldDisplayer.destroy().catch(() => {}); @@ -2635,7 +2568,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget { this.streamingEngine_.reloadTextStream(); } } else { - if (this.textDisplayer_ && this.textDisplayer_.configure) { + if (this.textDisplayer_) { this.textDisplayer_.configure(this.config_.textDisplayer); } } @@ -3044,7 +2977,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget { // Don't initialize with a text stream unless we should be streaming // text. - if (initialTextStream && this.isTextTrackVisible()) { + if (initialTextStream && this.isTextVisible_) { this.streamingEngine_.switchTextStream(initialTextStream); this.setTextDisplayerLanguage_(); } @@ -3224,14 +3157,6 @@ shaka.Player = class extends shaka.util.FakeEventTarget { if (track) { track.mode = showing ? 'showing' : 'hidden'; } - if (this.textDisplayer_ instanceof shaka.text.SimpleTextDisplayer) { - const generatedTrack = this.getGeneratedTextTrack_(); - if (generatedTrack) { - generatedTrack.mode = - !showing && this.textDisplayer_.isTextVisible() ? - 'showing' : 'hidden'; - } - } } }; this.loadEventManager_.listen(mediaElement, 'enterpictureinpicture', @@ -3376,15 +3301,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget { !(this.textDisplayer_ instanceof shaka.text.NativeTextDisplayer) ) { if (textTracks.length) { - if (this.textDisplayer_.enableTextDisplayer) { - this.textDisplayer_.enableTextDisplayer(); - } else { - shaka.Deprecate.deprecateFeature( - 5, - 'Text displayer w/ enableTextDisplayer', - 'Text displayer should have a "enableTextDisplayer" method', - ); - } + this.textDisplayer_.enableTextDisplayer(); } let enabledNativeTrack = false; @@ -3481,8 +3398,16 @@ shaka.Player = class extends shaka.util.FakeEventTarget { return; } - const preferredAudioRole = this.config_.preferredAudioRole; - this.selectAudioLanguage(preferredAudioLanguage, preferredAudioRole); + if (this.video_ && this.video_.audioTracks) { + const track = shaka.util.StreamUtils.filterStreamsByLanguageAndRole( + this.getVariantTracks(), + preferredAudioLanguage, + this.config_.preferredAudioRole, + false)[0]; + if (track) { + this.selectVariantTrack(track); + } + } } /** @@ -3499,11 +3424,14 @@ shaka.Player = class extends shaka.util.FakeEventTarget { return; } - const preferForcedSubs = this.config_.preferForcedSubs; - const preferredTextRole = this.config_.preferredTextRole; - - this.selectTextLanguage(preferredTextLanguage, preferredTextRole, - preferForcedSubs); + const track = shaka.util.StreamUtils.filterStreamsByLanguageAndRole( + this.getTextTracks(), + preferredTextLanguage, + this.config_.preferredTextRole, + this.config_.preferForcedSubs)[0]; + if (track) { + this.selectTextTrack(track); + } } /** @@ -4278,352 +4206,6 @@ shaka.Player = class extends shaka.util.FakeEventTarget { goog.asserts.assert(typeof(config) == 'object', 'Should be an object!'); - // Deprecate 'preferredVariantRole' configuration. - if ('preferredVariantRole' in config) { - shaka.Deprecate.deprecateFeature(5, - 'preferredVariantRole configuration', - 'Please Use preferredAudioRole instead.'); - config['preferredAudioRole'] = config['preferredVariantRole']; - delete config['preferredVariantRole']; - } - - // Deprecate 'streaming.forceTransmuxTS' configuration. - if (config['streaming'] && 'forceTransmuxTS' in config['streaming']) { - shaka.Deprecate.deprecateFeature(5, - 'streaming.forceTransmuxTS configuration', - 'Please Use mediaSource.forceTransmux instead.'); - config['mediaSource'] = config['mediaSource'] || {}; - config['mediaSource']['mediaSource'] = - config['streaming']['forceTransmuxTS']; - delete config['streaming']['forceTransmuxTS']; - } - - // Deprecate 'streaming.forceTransmux' configuration. - if (config['streaming'] && 'forceTransmux' in config['streaming']) { - shaka.Deprecate.deprecateFeature(5, - 'streaming.forceTransmux configuration', - 'Please Use mediaSource.forceTransmux instead.'); - config['mediaSource'] = config['mediaSource'] || {}; - config['mediaSource']['mediaSource'] = - config['streaming']['forceTransmux']; - delete config['streaming']['forceTransmux']; - } - - // Deprecate 'streaming.useNativeHlsOnSafari' configuration. - if (config['streaming'] && 'useNativeHlsOnSafari' in config['streaming']) { - shaka.Deprecate.deprecateFeature(5, - 'streaming.useNativeHlsOnSafari configuration', - 'Please Use streaming.useNativeHlsForFairPlay or ' + - 'streaming.preferNativeHls instead.'); - const device = shaka.device.DeviceFactory.getDevice(); - config['streaming']['preferNativeHls'] = - config['streaming']['useNativeHlsOnSafari'] && - device.getBrowserEngine() === - shaka.device.IDevice.BrowserEngine.WEBKIT; - delete config['streaming']['useNativeHlsOnSafari']; - } - - // Deprecate 'streaming.liveSync' boolean configuration. - if (config['streaming'] && - typeof config['streaming']['liveSync'] == 'boolean') { - shaka.Deprecate.deprecateFeature(5, - 'streaming.liveSync', - 'Please Use streaming.liveSync.enabled instead.'); - const liveSyncValue = config['streaming']['liveSync']; - config['streaming']['liveSync'] = {}; - config['streaming']['liveSync']['enabled'] = liveSyncValue; - } - - // map liveSyncMinLatency and liveSyncMaxLatency to liveSync.targetLatency - // if liveSync.targetLatency isn't set. - if (config['streaming'] && (!config['streaming']['liveSync'] || - !('targetLatency' in config['streaming']['liveSync'])) && - ('liveSyncMinLatency' in config['streaming'] || - 'liveSyncMaxLatency' in config['streaming'])) { - const min = config['streaming']['liveSyncMinLatency'] || 0; - const max = config['streaming']['liveSyncMaxLatency'] || 1; - const mid = Math.abs(max - min) / 2; - config['streaming']['liveSync'] = config['streaming']['liveSync'] || {}; - config['streaming']['liveSync']['targetLatency'] = min + mid; - config['streaming']['liveSync']['targetLatencyTolerance'] = mid; - } - // Deprecate 'streaming.liveSyncMaxLatency' configuration. - if (config['streaming'] && 'liveSyncMaxLatency' in config['streaming']) { - shaka.Deprecate.deprecateFeature(5, - 'streaming.liveSyncMaxLatency', - 'Please Use streaming.liveSync.targetLatency and ' + - 'streaming.liveSync.targetLatencyTolerance instead. ' + - 'Or, set the values in your DASH manifest'); - delete config['streaming']['liveSyncMaxLatency']; - } - // Deprecate 'streaming.liveSyncMinLatency' configuration. - if (config['streaming'] && 'liveSyncMinLatency' in config['streaming']) { - shaka.Deprecate.deprecateFeature(5, - 'streaming.liveSyncMinLatency', - 'Please Use streaming.liveSync.targetLatency and ' + - 'streaming.liveSync.targetLatencyTolerance instead. ' + - 'Or, set the values in your DASH manifest'); - delete config['streaming']['liveSyncMinLatency']; - } - - // Deprecate 'streaming.liveSyncTargetLatency' configuration. - if (config['streaming'] && 'liveSyncTargetLatency' in config['streaming']) { - shaka.Deprecate.deprecateFeature(5, - 'streaming.liveSyncTargetLatency', - 'Please Use streaming.liveSync.targetLatency instead.'); - config['streaming']['liveSync'] = config['streaming']['liveSync'] || {}; - config['streaming']['liveSync']['targetLatency'] = - config['streaming']['liveSyncTargetLatency']; - delete config['streaming']['liveSyncTargetLatency']; - } - - // Deprecate 'streaming.liveSyncTargetLatencyTolerance' configuration. - if (config['streaming'] && - 'liveSyncTargetLatencyTolerance' in config['streaming']) { - shaka.Deprecate.deprecateFeature(5, - 'streaming.liveSyncTargetLatencyTolerance', - 'Please Use streaming.liveSync.targetLatencyTolerance instead.'); - config['streaming']['liveSync'] = config['streaming']['liveSync'] || {}; - config['streaming']['liveSync']['targetLatencyTolerance'] = - config['streaming']['liveSyncTargetLatencyTolerance']; - delete config['streaming']['liveSyncTargetLatencyTolerance']; - } - - // Deprecate 'streaming.liveSyncPlaybackRate' configuration. - if (config['streaming'] && 'liveSyncPlaybackRate' in config['streaming']) { - shaka.Deprecate.deprecateFeature(5, - 'streaming.liveSyncPlaybackRate', - 'Please Use streaming.liveSync.maxPlaybackRate instead.'); - config['streaming']['liveSync'] = config['streaming']['liveSync'] || {}; - config['streaming']['liveSync']['maxPlaybackRate'] = - config['streaming']['liveSyncPlaybackRate']; - delete config['streaming']['liveSyncPlaybackRate']; - } - - // Deprecate 'streaming.liveSyncMinPlaybackRate' configuration. - if (config['streaming'] && - 'liveSyncMinPlaybackRate' in config['streaming']) { - shaka.Deprecate.deprecateFeature(5, - 'streaming.liveSyncMinPlaybackRate', - 'Please Use streaming.liveSync.minPlaybackRate instead.'); - config['streaming']['liveSync'] = config['streaming']['liveSync'] || {}; - config['streaming']['liveSync']['minPlaybackRate'] = - config['streaming']['liveSyncMinPlaybackRate']; - delete config['streaming']['liveSyncMinPlaybackRate']; - } - - // Deprecate 'streaming.liveSyncPanicMode' configuration. - if (config['streaming'] && 'liveSyncPanicMode' in config['streaming']) { - shaka.Deprecate.deprecateFeature(5, - 'streaming.liveSyncPanicMode', - 'Please Use streaming.liveSync.panicMode instead.'); - config['streaming']['liveSync'] = config['streaming']['liveSync'] || {}; - config['streaming']['liveSync']['panicMode'] = - config['streaming']['liveSyncPanicMode']; - delete config['streaming']['liveSyncPanicMode']; - } - - // Deprecate 'streaming.liveSyncPanicThreshold' configuration. - if (config['streaming'] && - 'liveSyncPanicThreshold' in config['streaming']) { - shaka.Deprecate.deprecateFeature(5, - 'streaming.liveSyncPanicThreshold', - 'Please Use streaming.liveSync.panicThreshold instead.'); - config['streaming']['liveSync'] = config['streaming']['liveSync'] || {}; - config['streaming']['liveSync']['panicThreshold'] = - config['streaming']['liveSyncPanicThreshold']; - delete config['streaming']['liveSyncPanicThreshold']; - } - - // Deprecate 'mediaSource.sourceBufferExtraFeatures' configuration. - if (config['mediaSource'] && - 'sourceBufferExtraFeatures' in config['mediaSource']) { - shaka.Deprecate.deprecateFeature(5, - 'mediaSource.sourceBufferExtraFeatures configuration', - 'Please Use mediaSource.addExtraFeaturesToSourceBuffer() instead.'); - const sourceBufferExtraFeatures = - config['mediaSource']['sourceBufferExtraFeatures']; - config['mediaSource']['addExtraFeaturesToSourceBuffer'] = () => { - return sourceBufferExtraFeatures; - }; - delete config['mediaSource']['sourceBufferExtraFeatures']; - } - - // Deprecate 'manifest.hls.useSafariBehaviorForLive' configuration. - if (config['manifest'] && config['manifest']['hls'] && - 'useSafariBehaviorForLive' in config['manifest']['hls']) { - shaka.Deprecate.deprecateFeature(5, - 'manifest.hls.useSafariBehaviorForLive configuration', - 'Please Use liveSync config to keep on live Edge instead.'); - delete config['manifest']['hls']['useSafariBehaviorForLive']; - } - - // Deprecate 'streaming.parsePrftBox' configuration. - if (config['streaming'] && 'parsePrftBox' in config['streaming']) { - shaka.Deprecate.deprecateFeature(5, - 'streaming.parsePrftBox configuration', - 'Now fired without needing a configuration.'); - delete config['streaming']['parsePrftBox']; - } - - // Deprecate 'manifest.dash.enableAudioGroups' configuration. - if (config['manifest'] && config['manifest']['dash'] && - 'enableAudioGroups' in config['manifest']['dash']) { - shaka.Deprecate.deprecateFeature(5, - 'manifest.dash.enableAudioGroups configuration', - 'Please Use manifest.enableAudioGroups instead.'); - config['manifest']['enableAudioGroups'] = - config['manifest']['dash']['enableAudioGroups']; - delete config['manifest']['dash']['enableAudioGroups']; - } - - // Deprecate 'streaming.dispatchAllEmsgBoxes' configuration. - if (config['streaming'] && 'dispatchAllEmsgBoxes' in config['streaming']) { - shaka.Deprecate.deprecateFeature(5, - 'streaming.dispatchAllEmsgBoxes configuration', - 'Please Use mediaSource.dispatchAllEmsgBoxes instead.'); - config['mediaSource'] = config['mediaSource'] || {}; - config['mediaSource']['dispatchAllEmsgBoxes'] = - config['streaming']['dispatchAllEmsgBoxes']; - delete config['streaming']['dispatchAllEmsgBoxes']; - } - - // Deprecate 'streaming.autoLowLatencyMode' configuration. - if (config['streaming'] && 'autoLowLatencyMode' in config['streaming']) { - shaka.Deprecate.deprecateFeature(5, - 'streaming.autoLowLatencyMode configuration', - 'Please Use streaming.lowLatencyMode instead.'); - config['streaming']['lowLatencyMode'] = - config['streaming']['autoLowLatencyMode']; - delete config['streaming']['autoLowLatencyMode']; - } - - // Deprecate 'manifest.dash.ignoreSupplementalCodecs' configuration. - if (config['manifest'] && config['manifest']['dash'] && - 'ignoreSupplementalCodecs' in config['manifest']['dash']) { - shaka.Deprecate.deprecateFeature(5, - 'manifest.dash.ignoreSupplementalCodecs configuration', - 'Please Use manifest.ignoreSupplementalCodecs instead.'); - config['manifest']['ignoreSupplementalCodecs'] = - config['manifest']['dash']['ignoreSupplementalCodecs']; - delete config['manifest']['dash']['ignoreSupplementalCodecs']; - } - - // Deprecate 'manifest.hls.ignoreSupplementalCodecs' configuration. - if (config['manifest'] && config['manifest']['hls'] && - 'ignoreSupplementalCodecs' in config['manifest']['hls']) { - shaka.Deprecate.deprecateFeature(5, - 'manifest.hls.ignoreSupplementalCodecs configuration', - 'Please Use manifest.ignoreSupplementalCodecs instead.'); - config['manifest']['ignoreSupplementalCodecs'] = - config['manifest']['hls']['ignoreSupplementalCodecs']; - delete config['manifest']['hls']['ignoreSupplementalCodecs']; - } - - // Deprecate 'manifest.dash.updatePeriod' configuration. - if (config['manifest'] && config['manifest']['dash'] && - 'updatePeriod' in config['manifest']['dash']) { - shaka.Deprecate.deprecateFeature(5, - 'manifest.dash.updatePeriod configuration', - 'Please Use manifest.updatePeriod instead.'); - config['manifest']['updatePeriod'] = - config['manifest']['dash']['updatePeriod']; - delete config['manifest']['dash']['updatePeriod']; - } - - // Deprecate 'manifest.hls.updatePeriod' configuration. - if (config['manifest'] && config['manifest']['hls'] && - 'updatePeriod' in config['manifest']['hls']) { - shaka.Deprecate.deprecateFeature(5, - 'manifest.hls.updatePeriod configuration', - 'Please Use manifest.updatePeriod instead.'); - config['manifest']['updatePeriod'] = - config['manifest']['hls']['updatePeriod']; - delete config['manifest']['hls']['updatePeriod']; - } - - // Deprecate 'manifest.dash.ignoreDrmInfo' configuration. - if (config['manifest'] && config['manifest']['dash'] && - 'ignoreDrmInfo' in config['manifest']['dash']) { - shaka.Deprecate.deprecateFeature(5, - 'manifest.dash.ignoreDrmInfo configuration', - 'Please Use manifest.ignoreDrmInfo instead.'); - config['manifest']['ignoreDrmInfo'] = - config['manifest']['dash']['ignoreDrmInfo']; - delete config['manifest']['dash']['ignoreDrmInfo']; - } - - // Deprecate AdvancedDrmConfiguration's videoRobustness and audioRobustness - // as a string. It's now an array of strings. - if (config['drm'] && config['drm']['advanced']) { - let fixedUp = false; - for (const keySystem in config['drm']['advanced']) { - const {videoRobustness, audioRobustness} = - config['drm']['advanced'][keySystem]; - if ('videoRobustness' in config['drm']['advanced'][keySystem] && - !Array.isArray( - config['drm']['advanced'][keySystem]['videoRobustness'])) { - config['drm']['advanced'][keySystem]['videoRobustness'] = - [videoRobustness]; - fixedUp = true; - } - if ('audioRobustness' in config['drm']['advanced'][keySystem] && - !Array.isArray( - config['drm']['advanced'][keySystem]['audioRobustness'])) { - config['drm']['advanced'][keySystem]['audioRobustness'] = - [audioRobustness]; - fixedUp = true; - } - } - - if (fixedUp) { - shaka.Deprecate.deprecateFeature(5, - 'AdvancedDrmConfiguration\'s videoRobustness and audioRobustness', - 'These properties are no longer strings but array of strings, ' + - 'please update your usage of these properties.'); - } - } - - // Deprecate 'streaming.forceHTTP' configuration. - if (config['streaming'] && 'forceHTTP' in config['streaming']) { - shaka.Deprecate.deprecateFeature(5, - 'streaming.forceHTTP configuration', - 'Please Use networking.forceHTTP instead.'); - config['networking'] = config['networking'] || {}; - config['networking']['forceHTTP'] = config['streaming']['forceHTTP']; - delete config['streaming']['forceHTTP']; - } - - // Deprecate 'streaming.forceHTTPS' configuration. - if (config['streaming'] && 'forceHTTPS' in config['streaming']) { - shaka.Deprecate.deprecateFeature(5, - 'streaming.forceHTTPS configuration', - 'Please Use networking.forceHTTP instead.'); - config['networking'] = config['networking'] || {}; - config['networking']['forceHTTPS'] = config['streaming']['forceHTTPS']; - delete config['streaming']['forceHTTPS']; - } - - // Deprecate 'streaming.minBytesForProgressEvents' configuration. - if (config['streaming'] && - 'minBytesForProgressEvents' in config['streaming']) { - shaka.Deprecate.deprecateFeature(5, - 'streaming.minBytesForProgressEvents configuration', - 'Please Use networking.minBytesForProgressEvents instead.'); - config['networking'] = config['networking'] || {}; - config['networking']['minBytesForProgressEvents'] = - config['streaming']['minBytesForProgressEvents']; - delete config['streaming']['minBytesForProgressEvents']; - } - - // Deprecate 'streaming.alwaysStreamText' configuration. - if (config['streaming'] && 'alwaysStreamText' in config['streaming']) { - shaka.Deprecate.deprecateFeature(5, - 'streaming.alwaysStreamText configuration', - 'It is no longer necessary since we included NativeTextDisplayer.'); - delete config['streaming']['alwaysStreamText']; - } - const ret = shaka.util.PlayerConfiguration.mergeConfigObjects( this.config_, config, this.defaultConfig_()); @@ -5730,20 +5312,20 @@ shaka.Player = class extends shaka.util.FakeEventTarget { * Note that AdaptationEvents are not fired for manual track * selections. * - * @param {?shaka.extern.TextTrack} track + * @param {(?shaka.extern.TextTrack|undefined)=} track * @export */ selectTextTrack(track) { let isSpeechToText = false; - if (this.speechToText_ && track != null) { + if (this.speechToText_ && track) { const speechToTextTracks = this.speechToText_.getTextTracks(); isSpeechToText = speechToTextTracks.includes(track); } if (this.speechToText_ && !isSpeechToText) { this.speechToText_.disable(); } - if (track == null || isSpeechToText) { - if (this.speechToText_ && isSpeechToText && track != null) { + if (!track || isSpeechToText) { + if (this.speechToText_ && isSpeechToText && track) { this.speechToText_.enable(track); } this.onTextChanged_(); @@ -6238,353 +5820,6 @@ shaka.Player = class extends shaka.util.FakeEventTarget { return Array.from(videoTracksMap.values()); } - /** - * Return a list of audio language-role combinations available. If the - * player has not loaded any content, this will return an empty list. - * - *
- * - * This API is deprecated and will be removed in version 5.0, please migrate - * to using `getAudioTracks` and `selectAudioTrack`. - * - * @return {!Array} - * @deprecated - * @export - */ - getAudioLanguagesAndRoles() { - return shaka.Player.getLanguageAndRolesFrom_(this.getVariantTracks()); - } - - /** - * Return a list of text language-role combinations available. If the player - * has not loaded any content, this will be return an empty list. - * - *
- * - * This API is deprecated and will be removed in version 5.0, please migrate - * to using `getTextTracks` and `selectTextTrack`. - * - * @return {!Array} - * @deprecated - * @export - */ - getTextLanguagesAndRoles() { - return shaka.Player.getLanguageAndRolesFrom_(this.getTextTracks()); - } - - /** - * Return a list of audio languages available. If the player has not loaded - * any content, this will return an empty list. - * - *
- * - * This API is deprecated and will be removed in version 5.0, please migrate - * to using `getAudioTracks` and `selectAudioTrack`. - * - * @return {!Array} - * @deprecated - * @export - */ - getAudioLanguages() { - return Array.from(shaka.Player.getLanguagesFrom_(this.getVariantTracks())); - } - - /** - * Return a list of text languages available. If the player has not loaded - * any content, this will return an empty list. - * - *
- * - * This API is deprecated and will be removed in version 5.0, please migrate - * to using `getTextTracks` and `selectTextTrack`. - * - * @return {!Array} - * @deprecated - * @export - */ - getTextLanguages() { - return Array.from(shaka.Player.getLanguagesFrom_(this.getTextTracks())); - } - - /** - * Sets the current audio language and current variant role to the selected - * language, role and channel count, and chooses a new variant if need be. - * If the player has not loaded any content, this will be a no-op. - * - *
- * - * This API is deprecated and will be removed in version 5.0, please migrate - * to using `getAudioTracks` and `selectAudioTrack`. - * - * @param {string} language - * @param {string=} role - * @param {number=} channelsCount - * @param {number=} safeMargin - * @param {string=} codec - * @param {boolean=} spatialAudio - * @param {string=} label - * @deprecated - * @export - */ - selectAudioLanguage(language, role, channelsCount = 0, safeMargin = 0, - codec = '', spatialAudio = false, label = '') { - const selectMediaSourceMode = () => { - const active = this.streamingEngine_.getCurrentVariant(); - this.currentAdaptationSetCriteria_ = - this.config_.adaptationSetCriteriaFactory(); - this.currentAdaptationSetCriteria_.configure({ - language, - role: role || '', - videoRole: (active.video && active.video.roles && - active.video.roles[0]) || '', - channelCount: channelsCount || 0, - hdrLevel: '', - spatialAudio: spatialAudio || false, - videoLayout: '', - audioLabel: label || '', - videoLabel: '', - codecSwitchingStrategy: - this.config_.mediaSource.codecSwitchingStrategy, - audioCodec: codec || '', - activeAudioCodec: active.audio && active.audio.codecs ? - active.audio.codecs : '', - activeAudioChannelCount: active.audio && active.audio.channelsCount ? - active.audio.channelsCount : 0, - preferredAudioCodecs: this.config_.preferredAudioCodecs, - preferredAudioChannelCount: this.config_.preferredAudioChannelCount, - }); - - const diff = (a, b) => { - if (!a.video && !b.video) { - return 0; - } else if (!a.video || !b.video) { - return Infinity; - } else { - return Math.abs((a.video.height || 0) - (b.video.height || 0)) + - Math.abs((a.video.width || 0) - (b.video.width || 0)); - } - }; - // Find the variant whose size is closest to the active variant. This - // ensures we stay at about the same resolution when just changing the - // language/role. - const set = - this.currentAdaptationSetCriteria_.create(this.manifest_.variants); - let bestVariant = null; - for (const curVariant of set.values()) { - if (!shaka.util.StreamUtils.isPlayable(curVariant)) { - continue; - } - if (!bestVariant || - diff(bestVariant, active) > diff(curVariant, active)) { - bestVariant = curVariant; - } - } - if (bestVariant == active) { - shaka.log.debug('Audio already selected.'); - return; - } - if (bestVariant) { - const track = shaka.util.StreamUtils.variantToTrack(bestVariant); - this.selectVariantTrack( - track, /* clearBuffer= */ true, safeMargin || 0); - return; - } - - // If we haven't switched yet, just use ABR to find a new track. - this.chooseVariantAndSwitch_(); - }; - const selectSrcEqualsMode = () => { - if (this.video_ && this.video_.audioTracks) { - const track = shaka.util.StreamUtils.filterStreamsByLanguageAndRole( - this.getVariantTracks(), language, role || '', false)[0]; - if (track) { - this.selectVariantTrack(track); - } - } - }; - if (this.manifest_ && this.playhead_) { - selectMediaSourceMode(); - // When using MSE + remote we need to set tracks for both MSE and native - // apis so that synchronization is maintained. - if (!this.isRemotePlayback()) { - return; - } - } - selectSrcEqualsMode(); - } - - /** - * Sets the current text language and current text role to the selected - * language and role, and chooses a new variant if need be. If the player has - * not loaded any content, this will be a no-op. - * - *
- * - * This API is deprecated and will be removed in version 5.0, please migrate - * to using `getTextTracks` and `selectTextTrack`. - * - * @param {string} language - * @param {string=} role - * @param {boolean=} forced - * @deprecated - * @export - */ - selectTextLanguage(language, role, forced = false) { - const selectMediaSourceMode = () => { - this.currentTextLanguage_ = language; - this.currentTextRole_ = role || ''; - this.currentTextForced_ = forced || false; - - const chosenText = this.chooseTextStream_(); - if (chosenText) { - if (chosenText == this.streamingEngine_.getCurrentTextStream()) { - shaka.log.debug('Text track already selected.'); - return; - } - - this.addTextStreamToSwitchHistory_( - chosenText, /* fromAdaptation= */ false); - if (this.isTextTrackVisible()) { - this.streamingEngine_.switchTextStream(chosenText); - this.onTextChanged_(); - this.setTextDisplayerLanguage_(); - } - } - }; - const selectSrcEqualsMode = () => { - const track = shaka.util.StreamUtils.filterStreamsByLanguageAndRole( - this.getTextTracks(), language, role || '', forced || false)[0]; - if (track) { - this.selectTextTrack(track); - } - }; - if (this.manifest_ && this.playhead_) { - selectMediaSourceMode(); - // When using MSE + remote we need to set tracks for both MSE and native - // apis so that synchronization is maintained. - if (!this.isRemotePlayback()) { - return; - } - } - selectSrcEqualsMode(); - } - - /** - * Select variant tracks that have a given label. This assumes the - * label uniquely identifies an audio stream, so all the variants - * are expected to have the same variant.audio. - * - * This API is deprecated and will be removed in version 5.0, please migrate - * to using `getAudioTracks` and `selectAudioTrack`. - * - * @param {string} label - * @param {boolean=} clearBuffer Optional clear buffer or not when - * switch to new variant - * Defaults to true if not provided - * @param {number=} safeMargin Optional amount of buffer (in seconds) to - * retain when clearing the buffer. - * Defaults to 0 if not provided. Ignored if clearBuffer is false. - * @deprecated - * @export - */ - selectVariantsByLabel(label, clearBuffer = true, safeMargin = 0) { - const selectMediaSourceMode = () => { - let firstVariantWithLabel = null; - for (const variant of this.manifest_.variants) { - if (variant.audio.label == label) { - firstVariantWithLabel = variant; - break; - } - } - - if (firstVariantWithLabel == null) { - shaka.log.warning('No variants were found with label: ' + - label + '. Ignoring the request to switch.'); - - return; - } - - // Label is a unique identifier of a variant's audio stream. - // Because of that we assume that all the variants with the same - // label have the same language. - this.currentAdaptationSetCriteria_ = - this.config_.adaptationSetCriteriaFactory(); - this.currentAdaptationSetCriteria_.configure({ - language: firstVariantWithLabel.language, - role: '', - videoRole: '', - channelCount: 0, - hdrLevel: '', - spatialAudio: false, - videoLayout: '', - videoLabel: '', - audioLabel: label, - codecSwitchingStrategy: - this.config_.mediaSource.codecSwitchingStrategy, - audioCodec: '', - activeAudioCodec: '', - activeAudioChannelCount: 0, - preferredAudioCodecs: this.config_.preferredAudioCodecs, - preferredAudioChannelCount: this.config_.preferredAudioChannelCount, - }); - - this.chooseVariantAndSwitch_(clearBuffer, safeMargin); - }; - const selectSrcEqualsMode = () => { - if (this.video_ && this.video_.audioTracks) { - const audioTracks = Array.from(this.video_.audioTracks); - - let trackMatch = null; - - for (const audioTrack of audioTracks) { - if (audioTrack.label == label) { - trackMatch = audioTrack; - } - } - if (trackMatch) { - this.switchHtml5Track_(trackMatch); - } - } - }; - if (this.manifest_ && this.playhead_) { - selectMediaSourceMode(); - // When using MSE + remote we need to set tracks for both MSE and native - // apis so that synchronization is maintained. - if (!this.isRemotePlayback()) { - return; - } - } - selectSrcEqualsMode(); - } - - /** - * Check if the text displayer is enabled. - * - *
- * - * This API is deprecated and will be removed in version 5.0. - * `getTextTracks` returns all available text tracks, but none may be - * active, meaning no track is displayed. - * - * @return {boolean} - * @export - * @deprecated - */ - isTextTrackVisible() { - const expected = this.isTextVisible_; - if (this.textDisplayer_) { - const actual = this.textDisplayer_.isTextVisible(); - goog.asserts.assert( - actual == expected, 'text visibility has fallen out of sync'); - - // Always return the actual value so that the app has the most accurate - // information (in the case that the values come out of sync in prod). - return actual; - } - - return expected; - } - /** * Return a list of chapters tracks. * @@ -6596,51 +5831,6 @@ shaka.Player = class extends shaka.util.FakeEventTarget { (text) => shaka.util.StreamUtils.textStreamToTrack(text)); } - /** - * This returns the list of chapters. - * - * @param {string} language - * @return {!Array} - * @export - */ - getChapters(language) { - shaka.Deprecate.deprecateFeature(5, - 'getChapters', - 'Please use an getChaptersAsync.'); - if (!this.externalChaptersStreams_.length) { - return []; - } - const LanguageUtils = shaka.util.LanguageUtils; - const inputLanguage = LanguageUtils.normalize(language); - const chapterStreams = this.externalChaptersStreams_ - .filter((c) => LanguageUtils.normalize(c.language) == inputLanguage); - if (!chapterStreams.length) { - return []; - } - const chapters = []; - const uniqueChapters = new Set(); - for (const chapterStream of chapterStreams) { - if (chapterStream.segmentIndex) { - chapterStream.segmentIndex.forEachTopLevelReference((ref) => { - const title = ref.getUris()[0]; - const id = ref.startTime + '-' + ref.endTime + '-' + title; - /** @type {shaka.extern.Chapter} */ - const chapter = { - id, - title, - startTime: ref.startTime, - endTime: ref.endTime, - }; - if (!uniqueChapters.has(id)) { - chapters.push(chapter); - uniqueChapters.add(id); - } - }); - } - } - return chapters; - } - /** * This returns the list of chapters. * @@ -6782,11 +5972,6 @@ shaka.Player = class extends shaka.util.FakeEventTarget { } else if (this.video_ && this.video_.src && this.video_.textTracks) { this.textDisplayer_.setTextVisibility(newVisibility); } - - // We need to fire the event after we have updated everything so that - // everything will be in a stable state when the app responds to the - // event. - this.onTextTrackVisibility_(); } /** @@ -8469,14 +7654,6 @@ shaka.Player = class extends shaka.util.FakeEventTarget { return this.abrManager_.chooseVariant(initialSelection); } else { const adaptationSetCriteria = this.currentAdaptationSetCriteria_; - if (typeof adaptationSetCriteria.getLastAdaptationSet != 'function') { - shaka.Deprecate.deprecateFeature(5, - 'AdaptationSetCriteria w/o getLastAdaptationSet', - 'Please use an AdaptationSetCriteria with getLastAdaptationSet.'); - adaptationSetCriteria.getLastAdaptationSet = () => { - return null; - }; - } const adaptationSet = adaptationSetCriteria.getLastAdaptationSet(); if (adaptationSet) { const variants = Array.from(adaptationSet.values()); @@ -8708,14 +7885,11 @@ shaka.Player = class extends shaka.util.FakeEventTarget { // If the cached value says to show text, then update the text displayer // since it defaults to not shown. this.textDisplayer_.setTextVisibility(true); - goog.asserts.assert(this.isTextTrackVisible(), - 'Should be streaming text'); } } else { this.isTextVisible_ = false; this.textDisplayer_.setTextVisibility(false); } - this.onTextTrackVisibility_(); } /** @@ -8895,13 +8069,6 @@ shaka.Player = class extends shaka.util.FakeEventTarget { this.delayDispatchEvent_(event); } - /** @private */ - onTextTrackVisibility_() { - const event = shaka.Player.makeEvent_( - shaka.util.FakeEvent.EventName.TextTrackVisibility); - this.delayDispatchEvent_(event); - } - /** @private */ onAbrStatusChanged_() { // Restore disabled variants if abr get disabled @@ -8919,8 +8086,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget { */ setTextDisplayerLanguage_() { const activeTextTrack = this.getTextTracks().find((t) => t.active); - if (activeTextTrack && - this.textDisplayer_ && this.textDisplayer_.setTextLanguage) { + if (activeTextTrack && this.textDisplayer_) { this.textDisplayer_.setTextLanguage(activeTextTrack.language); } } @@ -9139,7 +8305,6 @@ shaka.Player = class extends shaka.util.FakeEventTarget { endTime: region.endTime, id: region.id, timescale: region.timescale, - eventElement: region.eventElement, eventNode: region.eventNode, }; @@ -9413,92 +8578,6 @@ shaka.Player = class extends shaka.util.FakeEventTarget { } } - /** - * Get the normalized languages for a group of tracks. - * - * @param {!Array} tracks - * @return {!Set} - * @private - */ - static getLanguagesFrom_(tracks) { - const languages = new Set(); - - for (const track of tracks) { - if (track.language) { - languages.add(shaka.util.LanguageUtils.normalize(track.language)); - } else { - languages.add('und'); - } - } - - return languages; - } - - /** - * Get all permutations of normalized languages and role for a group of - * tracks. - * - * @param {!Array} tracks - * @return {!Array} - * @private - */ - static getLanguageAndRolesFrom_(tracks) { - /** @type {!Map} */ - const languageToRoles = new Map(); - /** @type {!Map>} */ - const languageRoleToLabel = new Map(); - - for (let i = 0; i < tracks.length; i++) { - const track = /** @type {shaka.extern.Track} */(tracks[i]); - let language = 'und'; - let roles = []; - - if (track.language) { - language = shaka.util.LanguageUtils.normalize(track.language); - } - - if (track.type == 'variant') { - roles = track.audioRoles; - } else { - roles = track.roles; - } - - if (!roles || !roles.length) { - // We must have an empty role so that we will still get a language-role - // entry from our Map. - roles = ['']; - } - - if (!languageToRoles.has(language)) { - languageToRoles.set(language, new Set()); - } - - for (const role of roles) { - languageToRoles.get(language).add(role); - if (track.label) { - if (!languageRoleToLabel.has(language)) { - languageRoleToLabel.set(language, new Map()); - } - languageRoleToLabel.get(language).set(role, track.label); - } - } - } - - // Flatten our map to an array of language-role pairs. - const pairings = []; - languageToRoles.forEach((roles, language) => { - for (const role of roles) { - let label = null; - if (languageRoleToLabel.has(language) && - languageRoleToLabel.get(language).has(role)) { - label = languageRoleToLabel.get(language).get(role); - } - pairings.push({language, role, label}); - } - }); - return pairings; - } - /** * Create an error for when we purposely interrupt a load operation. * diff --git a/lib/text/native_text_displayer.js b/lib/text/native_text_displayer.js index 357b326be..9e7b45d94 100644 --- a/lib/text/native_text_displayer.js +++ b/lib/text/native_text_displayer.js @@ -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); }; diff --git a/lib/text/simple_text_displayer.js b/lib/text/simple_text_displayer.js deleted file mode 100644 index af702f25b..000000000 --- a/lib/text/simple_text_displayer.js +++ /dev/null @@ -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'; - } - } -}; diff --git a/lib/text/text_engine.js b/lib/text/text_engine.js index 715a6b896..a54775999 100644 --- a/lib/text/text_engine.js +++ b/lib/text/text_engine.js @@ -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; } diff --git a/lib/util/fairplay_utils.js b/lib/util/fairplay_utils.js deleted file mode 100644 index 43aeea525..000000000 --- a/lib/util/fairplay_utils.js +++ /dev/null @@ -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 -}; diff --git a/lib/util/fake_event.js b/lib/util/fake_event.js index 7927c1ffb..9721569b7 100644 --- a/lib/util/fake_event.js +++ b/lib/util/fake_event.js @@ -195,7 +195,6 @@ shaka.util.FakeEvent.EventName = { StateChanged: 'statechanged', Streaming: 'streaming', TextChanged: 'textchanged', - TextTrackVisibility: 'texttrackvisibility', ThirdQuartile: 'thirdquartile', TimelineRegionAdded: 'timelineregionadded', TimelineRegionEnter: 'timelineregionenter', diff --git a/lib/util/player_configuration.js b/lib/util/player_configuration.js index bea4314f2..29c312495 100644 --- a/lib/util/player_configuration.js +++ b/lib/util/player_configuration.js @@ -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} diff --git a/lib/util/tXml.js b/lib/util/tXml.js index bcb5be362..807e179d1 100644 --- a/lib/util/tXml.js +++ b/lib/util/tXml.js @@ -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 diff --git a/lib/util/ts_parser.js b/lib/util/ts_parser.js index 576a56e5f..2f53e3fd8 100644 --- a/lib/util/ts_parser.js +++ b/lib/util/ts_parser.js @@ -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} - * @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 * diff --git a/project-words.txt b/project-words.txt index e2454ebcf..9f517d6c6 100644 --- a/project-words.txt +++ b/project-words.txt @@ -77,7 +77,6 @@ submenuopen textchanged textlang textrole -texttrackvisibility thirdquartile timeandseekrangeupdated timelineregionadded diff --git a/roadmap.md b/roadmap.md index 6da267bff..4ecf7c297 100644 --- a/roadmap.md +++ b/roadmap.md @@ -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 diff --git a/shaka-player.uncompiled.js b/shaka-player.uncompiled.js index 483481059..c17fd0064 100644 --- a/shaka-player.uncompiled.js +++ b/shaka-player.uncompiled.js @@ -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'); diff --git a/test/ads/interstitial_ad_manager_unit.js b/test/ads/interstitial_ad_manager_unit.js index 1e0481c76..ea218de0e 100644 --- a/test/ads/interstitial_ad_manager_unit.js +++ b/test/ads/interstitial_ad_manager_unit.js @@ -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, }; diff --git a/test/cast/cast_proxy_unit.js b/test/cast/cast_proxy_unit.js index 605ca4c3a..02cea0322 100644 --- a/test/cast/cast_proxy_unit.js +++ b/test/cast/cast_proxy_unit.js @@ -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) => { diff --git a/test/cast/cast_receiver_integration.js b/test/cast/cast_receiver_integration.js index d9102e4af..e33261143 100644 --- a/test/cast/cast_receiver_integration.js +++ b/test/cast/cast_receiver_integration.js @@ -99,9 +99,6 @@ filterDescribe('CastReceiver', castReceiverIntegrationSupport, () => { player: { configure: {}, }, - playerAfterLoad: { - setTextTrackVisibility: true, - }, video: { loop: true, playbackRate: 5, diff --git a/test/cast/cast_receiver_unit.js b/test/cast/cast_receiver_unit.js index 34b9f888f..cf173df36 100644 --- a/test/cast/cast_receiver_unit.js +++ b/test/cast/cast_receiver_unit.js @@ -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); }); diff --git a/test/dash/dash_parser_live_unit.js b/test/dash/dash_parser_live_unit.js index 264ad4999..e350e3e4c 100644 --- a/test/dash/dash_parser_live_unit.js +++ b/test/dash/dash_parser_live_unit.js @@ -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), }); }); diff --git a/test/media/region_observer_unit.js b/test/media/region_observer_unit.js index d572c3514..a7c6c31c8 100644 --- a/test/media/region_observer_unit.js +++ b/test/media/region_observer_unit.js @@ -365,7 +365,6 @@ describe('RegionObserver', () => { startTime: startTimeSeconds, endTime: endTimeSeconds, timescale: 1, - eventElement: null, eventNode: null, }; } diff --git a/test/media/region_timeline_unit.js b/test/media/region_timeline_unit.js index cc59815cd..e75633ccb 100644 --- a/test/media/region_timeline_unit.js +++ b/test/media/region_timeline_unit.js @@ -134,7 +134,6 @@ describe('RegionTimeline', () => { startTime: startTimeSeconds, endTime: endTimeSeconds, timescale: 1, - eventElement: null, eventNode: null, }; } diff --git a/test/player_integration.js b/test/player_integration.js index 58b591040..f89f92d05 100644 --- a/test/player_integration.js +++ b/test/player_integration.js @@ -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 diff --git a/test/player_src_equals_external.js b/test/player_src_equals_external.js index 439a35a92..94da981c6 100644 --- a/test/player_src_equals_external.js +++ b/test/player_src_equals_external.js @@ -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); diff --git a/test/player_src_equals_integration.js b/test/player_src_equals_integration.js index 0fc901f5d..4ddbdc7f7 100644 --- a/test/player_src_equals_integration.js +++ b/test/player_src_equals_integration.js @@ -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 diff --git a/test/player_unit.js b/test/player_unit.js index 7f2f6a6be..b6e5b9eae 100644 --- a/test/player_unit.js +++ b/test/player_unit.js @@ -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', () => { diff --git a/test/test/util/fake_ad_manager.js b/test/test/util/fake_ad_manager.js index c8d4de109..05f37819b 100644 --- a/test/test/util/fake_ad_manager.js +++ b/test/test/util/fake_ad_manager.js @@ -64,11 +64,6 @@ shaka.test.FakeAdManager = class extends shaka.util.FakeEventTarget { /** @override */ replaceServerSideAdTagParameters(adTagParameters) {} - /** @override */ - getServerSideCuePoints() { - return []; - } - /** @override */ getCuePoints() { return []; diff --git a/test/test/util/layout_tests.js b/test/test/util/layout_tests.js index 262d9ff48..4d8afaff4 100644 --- a/test/test/util/layout_tests.js +++ b/test/test/util/layout_tests.js @@ -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(); diff --git a/test/test/util/simple_fakes.js b/test/test/util/simple_fakes.js index 644fe7e7d..6b3e228ac 100644 --- a/test/test/util/simple_fakes.js +++ b/test/test/util/simple_fakes.js @@ -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'); } diff --git a/test/text/native_text_displayer_unit.js b/test/text/native_text_displayer_unit.js index a98ecc80f..b3fb41446 100644 --- a/test/text/native_text_displayer_unit.js +++ b/test/text/native_text_displayer_unit.js @@ -35,8 +35,6 @@ describe('NativeTextDisplayer', () => { expect(track).toBeTruthy(); track.active = true; }, - setTextTrackVisibility: (visible) => - displayer.setTextVisibility(visible), }; video = new shaka.test.FakeVideo(); /** @suppress {checkTypes} */ diff --git a/test/text/simple_text_displayer_unit.js b/test/text/simple_text_displayer_unit.js deleted file mode 100644 index 46e58d872..000000000 --- a/test/text/simple_text_displayer_unit.js +++ /dev/null @@ -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 = - 'Test1Test2Test3Test4'; - 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} 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))); - } -}); diff --git a/test/text/text_engine_unit.js b/test/text/text_engine_unit.js index 12099ae24..493469354 100644 --- a/test/text/text_engine_unit.js +++ b/test/text/text_engine_unit.js @@ -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, }; }; diff --git a/test/ui/ui_integration.js b/test/ui/ui_integration.js index e4db4a69a..dba53e057 100644 --- a/test/ui/ui_integration.js +++ b/test/ui/ui_integration.js @@ -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} languagesAndRoles + * @param {!Array} 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( diff --git a/test/util/tXml_unit.js b/test/util/tXml_unit.js index 94ab8fee8..afa51b064 100644 --- a/test/util/tXml_unit.js +++ b/test/util/tXml_unit.js @@ -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 = { diff --git a/ui/controls.js b/ui/controls.js index 919e20369..3342cd842 100644 --- a/ui/controls.js +++ b/ui/controls.js @@ -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_); } diff --git a/ui/text_selection.js b/ui/text_selection.js index 4ff7d6539..f016a1959 100644 --- a/ui/text_selection.js +++ b/ui/text_selection.js @@ -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_);