diff --git a/.eslintrc.js b/.eslintrc.js index 06cf1d416..2a48845a3 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -53,7 +53,6 @@ module.exports = { // }}} // Temporary Google style overrides while we get in compliance with the latest style guide {{{ - "indent": "off", "prefer-spread": "off", "require-jsdoc": "off", // }}} diff --git a/demo/cast_receiver/receiver_app.js b/demo/cast_receiver/receiver_app.js index 05baa6bf2..7d3fbc227 100644 --- a/demo/cast_receiver/receiver_app.js +++ b/demo/cast_receiver/receiver_app.js @@ -127,7 +127,7 @@ ShakaReceiver.prototype.appDataCallback_ = function(appData) { /** @private */ ShakaReceiver.prototype.checkIdle_ = function() { console.debug('status changed', - 'idle=', this.receiver_.isIdle()); + 'idle=', this.receiver_.isIdle()); // If the app is idle, show the idle card and set a timer to close the app. // Otherwise, hide the idle card and cancel the timer. diff --git a/demo/common/asset.js b/demo/common/asset.js index ec5eb70c3..0b1d3aa6d 100644 --- a/demo/common/asset.js +++ b/demo/common/asset.js @@ -128,7 +128,7 @@ const ShakaDemoAssetInfo = class { */ addFeature(feature) { goog.asserts.assert(feature != shakaAssets.Feature.STORED, - 'Assets should not be given the synthetic "STORED" ' + + 'Assets should not be given the synthetic "STORED" ' + 'property!'); this.features.push(feature); // Sort the features list, so that features are in a predictable order. @@ -280,8 +280,8 @@ const ShakaDemoAssetInfo = class { if (this.licenseRequestHeaders.size) { const filter = (requestType, request) => { return this.addLicenseRequestHeaders_(this.licenseRequestHeaders, - requestType, - request); + requestType, + request); }; networkingEngine.registerRequestFilter(filter); } @@ -300,7 +300,7 @@ const ShakaDemoAssetInfo = class { */ getConfiguration() { const config = /** @type {shaka.extern.PlayerConfiguration} */( - {drm: {}, manifest: {dash: {}}}); + {drm: {}, manifest: {dash: {}}}); if (this.licenseServers.size) { config.drm.servers = {}; this.licenseServers.forEach((value, key) => { @@ -350,10 +350,10 @@ const ShakaDemoAssetInfo = class { /** @return {!ShakaDemoAssetInfo} */ static makeBlankAsset() { return new ShakaDemoAssetInfo( - /* name= */ '', - /* iconUri= */ '', - /* manifestUri= */ '', - /* source= */ shakaAssets.Source.CUSTOM); + /* name= */ '', + /* iconUri= */ '', + /* manifestUri= */ '', + /* source= */ shakaAssets.Source.CUSTOM); } /** diff --git a/demo/common/assets.js b/demo/common/assets.js index 671639aac..fe99a3ef8 100644 --- a/demo/common/assets.js +++ b/demo/common/assets.js @@ -188,116 +188,116 @@ shakaAssets.testAssets = [ /* iconUri= */ 'https://storage.googleapis.com/shaka-asset-icons/dark_truth.png', /* manifestUri= */ 'https://storage.googleapis.com/shaka-demo-assets/bbb-dark-truths/dash.mpd', /* source= */ shakaAssets.Source.SHAKA) - .addFeature(shakaAssets.Feature.DASH) - .addFeature(shakaAssets.Feature.HIGH_DEFINITION) - .addFeature(shakaAssets.Feature.MP4) - .addFeature(shakaAssets.Feature.WEBM) - .addFeature(shakaAssets.Feature.OFFLINE), + .addFeature(shakaAssets.Feature.DASH) + .addFeature(shakaAssets.Feature.HIGH_DEFINITION) + .addFeature(shakaAssets.Feature.MP4) + .addFeature(shakaAssets.Feature.WEBM) + .addFeature(shakaAssets.Feature.OFFLINE), new ShakaDemoAssetInfo( /* name= */ 'Big Buck Bunny: the Dark Truths of a Video Dev Cartoon (HLS)', // eslint-disable-line max-len /* iconUri= */ 'https://storage.googleapis.com/shaka-asset-icons/dark_truth.png', /* manifestUri= */ 'https://storage.googleapis.com/shaka-demo-assets/bbb-dark-truths-hls/hls.m3u8', /* source= */ shakaAssets.Source.SHAKA) - .addDescription('A serious documentary about a problem plaguing video developers.') // eslint-disable-line max-len - .markAsFeatured('Big Buck Bunny: the Dark Truths') - .addFeature(shakaAssets.Feature.HLS) - .addFeature(shakaAssets.Feature.HIGH_DEFINITION) - .addFeature(shakaAssets.Feature.MP4) - .addFeature(shakaAssets.Feature.OFFLINE), + .addDescription('A serious documentary about a problem plaguing video developers.') // eslint-disable-line max-len + .markAsFeatured('Big Buck Bunny: the Dark Truths') + .addFeature(shakaAssets.Feature.HLS) + .addFeature(shakaAssets.Feature.HIGH_DEFINITION) + .addFeature(shakaAssets.Feature.MP4) + .addFeature(shakaAssets.Feature.OFFLINE), new ShakaDemoAssetInfo( /* name= */ 'Angel One (multicodec, multilingual)', /* iconUri= */ 'https://storage.googleapis.com/shaka-asset-icons/angel_one.png', /* manifestUri= */ 'https://storage.googleapis.com/shaka-demo-assets/angel-one/dash.mpd', /* source= */ shakaAssets.Source.SHAKA) - .addDescription('A clip from a classic Star Trek TNG episode, presented in MPEG-DASH.') // eslint-disable-line max-len - .markAsFeatured('Angel One') - .addFeature(shakaAssets.Feature.DASH) - .addFeature(shakaAssets.Feature.MP4) - .addFeature(shakaAssets.Feature.MULTIPLE_LANGUAGES) - .addFeature(shakaAssets.Feature.SUBTITLES) - .addFeature(shakaAssets.Feature.WEBM) - .addFeature(shakaAssets.Feature.WEBVTT) - .addFeature(shakaAssets.Feature.OFFLINE), + .addDescription('A clip from a classic Star Trek TNG episode, presented in MPEG-DASH.') // eslint-disable-line max-len + .markAsFeatured('Angel One') + .addFeature(shakaAssets.Feature.DASH) + .addFeature(shakaAssets.Feature.MP4) + .addFeature(shakaAssets.Feature.MULTIPLE_LANGUAGES) + .addFeature(shakaAssets.Feature.SUBTITLES) + .addFeature(shakaAssets.Feature.WEBM) + .addFeature(shakaAssets.Feature.WEBVTT) + .addFeature(shakaAssets.Feature.OFFLINE), new ShakaDemoAssetInfo( /* name= */ 'Angel One (multicodec, multilingual, Widevine)', /* iconUri= */ 'https://storage.googleapis.com/shaka-asset-icons/angel_one.png', /* manifestUri= */ 'https://storage.googleapis.com/shaka-demo-assets/angel-one-widevine/dash.mpd', /* source= */ shakaAssets.Source.SHAKA) - .addKeySystem(shakaAssets.KeySystem.WIDEVINE) - .addFeature(shakaAssets.Feature.DASH) - .addFeature(shakaAssets.Feature.MP4) - .addFeature(shakaAssets.Feature.MULTIPLE_LANGUAGES) - .addFeature(shakaAssets.Feature.SUBTITLES) - .addFeature(shakaAssets.Feature.MULTIKEY) - .addFeature(shakaAssets.Feature.WEBM) - .addFeature(shakaAssets.Feature.WEBVTT) - .addFeature(shakaAssets.Feature.OFFLINE) - .addLicenseServer('com.widevine.alpha', 'https://cwip-shaka-proxy.appspot.com/no_auth'), + .addKeySystem(shakaAssets.KeySystem.WIDEVINE) + .addFeature(shakaAssets.Feature.DASH) + .addFeature(shakaAssets.Feature.MP4) + .addFeature(shakaAssets.Feature.MULTIPLE_LANGUAGES) + .addFeature(shakaAssets.Feature.SUBTITLES) + .addFeature(shakaAssets.Feature.MULTIKEY) + .addFeature(shakaAssets.Feature.WEBM) + .addFeature(shakaAssets.Feature.WEBVTT) + .addFeature(shakaAssets.Feature.OFFLINE) + .addLicenseServer('com.widevine.alpha', 'https://cwip-shaka-proxy.appspot.com/no_auth'), new ShakaDemoAssetInfo( /* name= */ 'Angel One (multicodec, multilingual, ClearKey server)', /* iconUri= */ 'https://storage.googleapis.com/shaka-asset-icons/angel_one.png', /* manifestUri= */ 'https://storage.googleapis.com/shaka-demo-assets/angel-one-clearkey/dash.mpd', /* source= */ shakaAssets.Source.SHAKA) - .addKeySystem(shakaAssets.KeySystem.CLEAR_KEY) - .addFeature(shakaAssets.Feature.DASH) - .addFeature(shakaAssets.Feature.MP4) - .addFeature(shakaAssets.Feature.MULTIPLE_LANGUAGES) - .addFeature(shakaAssets.Feature.SUBTITLES) - .addFeature(shakaAssets.Feature.WEBM) - .addFeature(shakaAssets.Feature.WEBVTT) - .addFeature(shakaAssets.Feature.OFFLINE) - .addLicenseServer('org.w3.clearkey', 'https://cwip-shaka-proxy.appspot.com/clearkey?_u3wDe7erb7v8Lqt8A3QDQ=ABEiM0RVZneImaq7zN3u_w'), + .addKeySystem(shakaAssets.KeySystem.CLEAR_KEY) + .addFeature(shakaAssets.Feature.DASH) + .addFeature(shakaAssets.Feature.MP4) + .addFeature(shakaAssets.Feature.MULTIPLE_LANGUAGES) + .addFeature(shakaAssets.Feature.SUBTITLES) + .addFeature(shakaAssets.Feature.WEBM) + .addFeature(shakaAssets.Feature.WEBVTT) + .addFeature(shakaAssets.Feature.OFFLINE) + .addLicenseServer('org.w3.clearkey', 'https://cwip-shaka-proxy.appspot.com/clearkey?_u3wDe7erb7v8Lqt8A3QDQ=ABEiM0RVZneImaq7zN3u_w'), new ShakaDemoAssetInfo( /* name= */ 'Angel One (HLS, MP4, multilingual)', /* iconUri= */ 'https://storage.googleapis.com/shaka-asset-icons/angel_one.png', /* manifestUri= */ 'https://storage.googleapis.com/shaka-demo-assets/angel-one-hls/hls.m3u8', /* source= */ shakaAssets.Source.SHAKA) - .addFeature(shakaAssets.Feature.HLS) - .addFeature(shakaAssets.Feature.MP4) - .addFeature(shakaAssets.Feature.MULTIPLE_LANGUAGES) - .addFeature(shakaAssets.Feature.SUBTITLES) - .addFeature(shakaAssets.Feature.SURROUND) - .addFeature(shakaAssets.Feature.WEBVTT) - .addFeature(shakaAssets.Feature.OFFLINE), + .addFeature(shakaAssets.Feature.HLS) + .addFeature(shakaAssets.Feature.MP4) + .addFeature(shakaAssets.Feature.MULTIPLE_LANGUAGES) + .addFeature(shakaAssets.Feature.SUBTITLES) + .addFeature(shakaAssets.Feature.SURROUND) + .addFeature(shakaAssets.Feature.WEBVTT) + .addFeature(shakaAssets.Feature.OFFLINE), new ShakaDemoAssetInfo( /* name= */ 'Angel One (HLS, MP4, multilingual, Widevine)', /* iconUri= */ 'https://storage.googleapis.com/shaka-asset-icons/angel_one.png', /* manifestUri= */ 'https://storage.googleapis.com/shaka-demo-assets/angel-one-widevine-hls/hls.m3u8', /* source= */ shakaAssets.Source.SHAKA) - .addKeySystem(shakaAssets.KeySystem.WIDEVINE) - .addFeature(shakaAssets.Feature.HLS) - .addFeature(shakaAssets.Feature.MP4) - .addFeature(shakaAssets.Feature.MULTIPLE_LANGUAGES) - .addFeature(shakaAssets.Feature.SUBTITLES) - .addFeature(shakaAssets.Feature.SURROUND) - .addFeature(shakaAssets.Feature.MULTIKEY) - .addFeature(shakaAssets.Feature.WEBVTT) - .addFeature(shakaAssets.Feature.OFFLINE) - .addLicenseServer('com.widevine.alpha', 'https://cwip-shaka-proxy.appspot.com/no_auth'), + .addKeySystem(shakaAssets.KeySystem.WIDEVINE) + .addFeature(shakaAssets.Feature.HLS) + .addFeature(shakaAssets.Feature.MP4) + .addFeature(shakaAssets.Feature.MULTIPLE_LANGUAGES) + .addFeature(shakaAssets.Feature.SUBTITLES) + .addFeature(shakaAssets.Feature.SURROUND) + .addFeature(shakaAssets.Feature.MULTIKEY) + .addFeature(shakaAssets.Feature.WEBVTT) + .addFeature(shakaAssets.Feature.OFFLINE) + .addLicenseServer('com.widevine.alpha', 'https://cwip-shaka-proxy.appspot.com/no_auth'), new ShakaDemoAssetInfo( /* name= */ 'Sintel 4k (multicodec)', /* iconUri= */ 'https://storage.googleapis.com/shaka-asset-icons/sintel.png', /* manifestUri= */ 'https://storage.googleapis.com/shaka-demo-assets/sintel/dash.mpd', /* source= */ shakaAssets.Source.SHAKA) - .addFeature(shakaAssets.Feature.DASH) - .addFeature(shakaAssets.Feature.HIGH_DEFINITION) - .addFeature(shakaAssets.Feature.MP4) - .addFeature(shakaAssets.Feature.SUBTITLES) - .addFeature(shakaAssets.Feature.ULTRA_HIGH_DEFINITION) - .addFeature(shakaAssets.Feature.WEBM) - .addFeature(shakaAssets.Feature.WEBVTT) - .addFeature(shakaAssets.Feature.OFFLINE), + .addFeature(shakaAssets.Feature.DASH) + .addFeature(shakaAssets.Feature.HIGH_DEFINITION) + .addFeature(shakaAssets.Feature.MP4) + .addFeature(shakaAssets.Feature.SUBTITLES) + .addFeature(shakaAssets.Feature.ULTRA_HIGH_DEFINITION) + .addFeature(shakaAssets.Feature.WEBM) + .addFeature(shakaAssets.Feature.WEBVTT) + .addFeature(shakaAssets.Feature.OFFLINE), new ShakaDemoAssetInfo( /* name= */ 'Sintel w/ trick mode (MP4 only, 720p)', /* iconUri= */ 'https://storage.googleapis.com/shaka-asset-icons/sintel.png', /* manifestUri= */ 'https://storage.googleapis.com/shaka-demo-assets/sintel-trickplay/dash.mpd', /* source= */ shakaAssets.Source.SHAKA) - .addFeature(shakaAssets.Feature.DASH) - .addFeature(shakaAssets.Feature.MP4) - .addFeature(shakaAssets.Feature.SUBTITLES) - .addFeature(shakaAssets.Feature.TRICK_MODE) - .addFeature(shakaAssets.Feature.WEBVTT) - .addFeature(shakaAssets.Feature.OFFLINE), + .addFeature(shakaAssets.Feature.DASH) + .addFeature(shakaAssets.Feature.MP4) + .addFeature(shakaAssets.Feature.SUBTITLES) + .addFeature(shakaAssets.Feature.TRICK_MODE) + .addFeature(shakaAssets.Feature.WEBVTT) + .addFeature(shakaAssets.Feature.OFFLINE), // NOTE: hanging in Firefox // https://bugzilla.mozilla.org/show_bug.cgi?id=1291451 new ShakaDemoAssetInfo( @@ -305,87 +305,87 @@ shakaAssets.testAssets = [ /* iconUri= */ 'https://storage.googleapis.com/shaka-asset-icons/sintel.png', /* manifestUri= */ 'https://storage.googleapis.com/shaka-demo-assets/sintel-webm-only/dash.mpd', /* source= */ shakaAssets.Source.SHAKA) - .addFeature(shakaAssets.Feature.DASH) - .addFeature(shakaAssets.Feature.HIGH_DEFINITION) - .addFeature(shakaAssets.Feature.SUBTITLES) - .addFeature(shakaAssets.Feature.ULTRA_HIGH_DEFINITION) - .addFeature(shakaAssets.Feature.WEBM) - .addFeature(shakaAssets.Feature.WEBVTT) - .addFeature(shakaAssets.Feature.OFFLINE), + .addFeature(shakaAssets.Feature.DASH) + .addFeature(shakaAssets.Feature.HIGH_DEFINITION) + .addFeature(shakaAssets.Feature.SUBTITLES) + .addFeature(shakaAssets.Feature.ULTRA_HIGH_DEFINITION) + .addFeature(shakaAssets.Feature.WEBM) + .addFeature(shakaAssets.Feature.WEBVTT) + .addFeature(shakaAssets.Feature.OFFLINE), new ShakaDemoAssetInfo( /* name= */ 'Sintel 4k (MP4 only)', /* iconUri= */ 'https://storage.googleapis.com/shaka-asset-icons/sintel.png', /* manifestUri= */ 'https://storage.googleapis.com/shaka-demo-assets/sintel-mp4-only/dash.mpd', /* source= */ shakaAssets.Source.SHAKA) - .addFeature(shakaAssets.Feature.DASH) - .addFeature(shakaAssets.Feature.HIGH_DEFINITION) - .addFeature(shakaAssets.Feature.MP4) - .addFeature(shakaAssets.Feature.SUBTITLES) - .addFeature(shakaAssets.Feature.ULTRA_HIGH_DEFINITION) - .addFeature(shakaAssets.Feature.WEBVTT) - .addFeature(shakaAssets.Feature.OFFLINE), + .addFeature(shakaAssets.Feature.DASH) + .addFeature(shakaAssets.Feature.HIGH_DEFINITION) + .addFeature(shakaAssets.Feature.MP4) + .addFeature(shakaAssets.Feature.SUBTITLES) + .addFeature(shakaAssets.Feature.ULTRA_HIGH_DEFINITION) + .addFeature(shakaAssets.Feature.WEBVTT) + .addFeature(shakaAssets.Feature.OFFLINE), new ShakaDemoAssetInfo( /* name= */ 'Sintel 4k (multicodec, Widevine)', /* iconUri= */ 'https://storage.googleapis.com/shaka-asset-icons/sintel.png', /* manifestUri= */ 'https://storage.googleapis.com/shaka-demo-assets/sintel-widevine/dash.mpd', /* source= */ shakaAssets.Source.SHAKA) - .addDescription('A Blender Foundation short film, protected by Widevine encryption.') // eslint-disable-line max-len - .markAsFeatured('Sintel') - .addKeySystem(shakaAssets.KeySystem.WIDEVINE) - .addFeature(shakaAssets.Feature.DASH) - .addFeature(shakaAssets.Feature.HIGH_DEFINITION) - .addFeature(shakaAssets.Feature.MP4) - .addFeature(shakaAssets.Feature.MULTIKEY) - .addFeature(shakaAssets.Feature.SUBTITLES) - .addFeature(shakaAssets.Feature.ULTRA_HIGH_DEFINITION) - .addFeature(shakaAssets.Feature.WEBM) - .addFeature(shakaAssets.Feature.WEBVTT) - .addFeature(shakaAssets.Feature.OFFLINE) - .addLicenseServer('com.widevine.alpha', 'https://cwip-shaka-proxy.appspot.com/no_auth'), + .addDescription('A Blender Foundation short film, protected by Widevine encryption.') // eslint-disable-line max-len + .markAsFeatured('Sintel') + .addKeySystem(shakaAssets.KeySystem.WIDEVINE) + .addFeature(shakaAssets.Feature.DASH) + .addFeature(shakaAssets.Feature.HIGH_DEFINITION) + .addFeature(shakaAssets.Feature.MP4) + .addFeature(shakaAssets.Feature.MULTIKEY) + .addFeature(shakaAssets.Feature.SUBTITLES) + .addFeature(shakaAssets.Feature.ULTRA_HIGH_DEFINITION) + .addFeature(shakaAssets.Feature.WEBM) + .addFeature(shakaAssets.Feature.WEBVTT) + .addFeature(shakaAssets.Feature.OFFLINE) + .addLicenseServer('com.widevine.alpha', 'https://cwip-shaka-proxy.appspot.com/no_auth'), new ShakaDemoAssetInfo( /* name= */ 'Sintel 4k (multicodec, VTT in MP4)', /* iconUri= */ 'https://storage.googleapis.com/shaka-asset-icons/sintel.png', /* manifestUri= */ 'https://storage.googleapis.com/shaka-demo-assets/sintel-mp4-wvtt/dash.mpd', /* source= */ shakaAssets.Source.SHAKA) - .addFeature(shakaAssets.Feature.DASH) - .addFeature(shakaAssets.Feature.HIGH_DEFINITION) - .addFeature(shakaAssets.Feature.MP4) - .addFeature(shakaAssets.Feature.SUBTITLES) - .addFeature(shakaAssets.Feature.ULTRA_HIGH_DEFINITION) - .addFeature(shakaAssets.Feature.WEBVTT) - .addFeature(shakaAssets.Feature.OFFLINE), + .addFeature(shakaAssets.Feature.DASH) + .addFeature(shakaAssets.Feature.HIGH_DEFINITION) + .addFeature(shakaAssets.Feature.MP4) + .addFeature(shakaAssets.Feature.SUBTITLES) + .addFeature(shakaAssets.Feature.ULTRA_HIGH_DEFINITION) + .addFeature(shakaAssets.Feature.WEBVTT) + .addFeature(shakaAssets.Feature.OFFLINE), new ShakaDemoAssetInfo( /* name= */ 'Sintel w/ 44 subtitle languages', /* iconUri= */ 'https://storage.googleapis.com/shaka-asset-icons/sintel.png', /* manifestUri= */ 'https://storage.googleapis.com/shaka-demo-assets/sintel-many-subs/dash.mpd', /* source= */ shakaAssets.Source.SHAKA) - .addFeature(shakaAssets.Feature.DASH) - .addFeature(shakaAssets.Feature.MP4) - .addFeature(shakaAssets.Feature.SUBTITLES) - .addFeature(shakaAssets.Feature.SURROUND) - .addFeature(shakaAssets.Feature.WEBVTT) - .addFeature(shakaAssets.Feature.OFFLINE), + .addFeature(shakaAssets.Feature.DASH) + .addFeature(shakaAssets.Feature.MP4) + .addFeature(shakaAssets.Feature.SUBTITLES) + .addFeature(shakaAssets.Feature.SURROUND) + .addFeature(shakaAssets.Feature.WEBVTT) + .addFeature(shakaAssets.Feature.OFFLINE), new ShakaDemoAssetInfo( /* name= */ 'Heliocentrism (multicodec, multiperiod)', /* iconUri= */ 'https://storage.googleapis.com/shaka-asset-icons/heliocentricism.png', /* manifestUri= */ 'https://storage.googleapis.com/shaka-demo-assets/heliocentrism/heliocentrism.mpd', /* source= */ shakaAssets.Source.SHAKA) - .addFeature(shakaAssets.Feature.DASH) - .addFeature(shakaAssets.Feature.MP4) - .addFeature(shakaAssets.Feature.MULTIPERIOD) - .addFeature(shakaAssets.Feature.WEBM) - .addFeature(shakaAssets.Feature.OFFLINE), + .addFeature(shakaAssets.Feature.DASH) + .addFeature(shakaAssets.Feature.MP4) + .addFeature(shakaAssets.Feature.MULTIPERIOD) + .addFeature(shakaAssets.Feature.WEBM) + .addFeature(shakaAssets.Feature.OFFLINE), new ShakaDemoAssetInfo( /* name= */ 'Heliocentrism (multicodec, multiperiod, xlink)', /* iconUri= */ 'https://storage.googleapis.com/shaka-asset-icons/heliocentricism.png', /* manifestUri= */ 'https://storage.googleapis.com/shaka-demo-assets/heliocentrism-xlink/heliocentrism.mpd', /* source= */ shakaAssets.Source.SHAKA) - .addFeature(shakaAssets.Feature.DASH) - .addFeature(shakaAssets.Feature.MP4) - .addFeature(shakaAssets.Feature.MULTIPERIOD) - .addFeature(shakaAssets.Feature.WEBM) - .addFeature(shakaAssets.Feature.XLINK) - .addFeature(shakaAssets.Feature.OFFLINE), + .addFeature(shakaAssets.Feature.DASH) + .addFeature(shakaAssets.Feature.MP4) + .addFeature(shakaAssets.Feature.MULTIPERIOD) + .addFeature(shakaAssets.Feature.WEBM) + .addFeature(shakaAssets.Feature.XLINK) + .addFeature(shakaAssets.Feature.OFFLINE), // From: http://dig.ccmixter.org/files/JeffSpeed68/53327 // Licensed under Creative Commons BY-NC 3.0. // Free for non-commercial use with attribution. @@ -395,13 +395,13 @@ shakaAssets.testAssets = [ /* iconUri= */ 'https://storage.googleapis.com/shaka-asset-icons/audio_only.png', /* manifestUri= */ 'https://storage.googleapis.com/shaka-demo-assets/dig-the-uke-clear/dash.mpd', /* source= */ shakaAssets.Source.SHAKA) - .addDescription('An audio-only presentation performed by Stefan Kartenberg.') // eslint-disable-line max-len - .markAsFeatured('Dig the Uke') - .addFeature(shakaAssets.Feature.DASH) - .addFeature(shakaAssets.Feature.MP4) - .addFeature(shakaAssets.Feature.AUDIO_ONLY) - .addFeature(shakaAssets.Feature.WEBM) - .addFeature(shakaAssets.Feature.OFFLINE), + .addDescription('An audio-only presentation performed by Stefan Kartenberg.') // eslint-disable-line max-len + .markAsFeatured('Dig the Uke') + .addFeature(shakaAssets.Feature.DASH) + .addFeature(shakaAssets.Feature.MP4) + .addFeature(shakaAssets.Feature.AUDIO_ONLY) + .addFeature(shakaAssets.Feature.WEBM) + .addFeature(shakaAssets.Feature.OFFLINE), // From: http://dig.ccmixter.org/files/JeffSpeed68/53327 // Licensed under Creative Commons BY-NC 3.0. // Free for non-commercial use with attribution. @@ -411,56 +411,56 @@ shakaAssets.testAssets = [ /* iconUri= */ 'https://storage.googleapis.com/shaka-asset-icons/audio_only.png', /* manifestUri= */ 'https://storage.googleapis.com/shaka-demo-assets/dig-the-uke/dash.mpd', /* source= */ shakaAssets.Source.SHAKA) - .addKeySystem(shakaAssets.KeySystem.WIDEVINE) - .addFeature(shakaAssets.Feature.DASH) - .addFeature(shakaAssets.Feature.MP4) - .addFeature(shakaAssets.Feature.AUDIO_ONLY) - .addFeature(shakaAssets.Feature.WEBM) - .addFeature(shakaAssets.Feature.OFFLINE) - .addLicenseServer('com.widevine.alpha', 'https://cwip-shaka-proxy.appspot.com/no_auth'), + .addKeySystem(shakaAssets.KeySystem.WIDEVINE) + .addFeature(shakaAssets.Feature.DASH) + .addFeature(shakaAssets.Feature.MP4) + .addFeature(shakaAssets.Feature.AUDIO_ONLY) + .addFeature(shakaAssets.Feature.WEBM) + .addFeature(shakaAssets.Feature.OFFLINE) + .addLicenseServer('com.widevine.alpha', 'https://cwip-shaka-proxy.appspot.com/no_auth'), new ShakaDemoAssetInfo( /* name= */ 'Tears of Steel (multicodec, TTML)', /* iconUri= */ 'https://storage.googleapis.com/shaka-asset-icons/tears_of_steel.png', /* manifestUri= */ 'https://storage.googleapis.com/shaka-demo-assets/tos-ttml/dash.mpd', /* source= */ shakaAssets.Source.SHAKA) - .addFeature(shakaAssets.Feature.DASH) - .addFeature(shakaAssets.Feature.HIGH_DEFINITION) - .addFeature(shakaAssets.Feature.MP4) - .addFeature(shakaAssets.Feature.SUBTITLES) - .addFeature(shakaAssets.Feature.TTML) - .addFeature(shakaAssets.Feature.WEBM) - .addFeature(shakaAssets.Feature.OFFLINE), + .addFeature(shakaAssets.Feature.DASH) + .addFeature(shakaAssets.Feature.HIGH_DEFINITION) + .addFeature(shakaAssets.Feature.MP4) + .addFeature(shakaAssets.Feature.SUBTITLES) + .addFeature(shakaAssets.Feature.TTML) + .addFeature(shakaAssets.Feature.WEBM) + .addFeature(shakaAssets.Feature.OFFLINE), new ShakaDemoAssetInfo( /* name= */ 'Tears of Steel (multicodec, surround + stereo)', /* iconUri= */ 'https://storage.googleapis.com/shaka-asset-icons/tears_of_steel.png', /* manifestUri= */ 'https://storage.googleapis.com/shaka-demo-assets/tos-surround/dash.mpd', /* source= */ shakaAssets.Source.SHAKA) - .addFeature(shakaAssets.Feature.DASH) - .addFeature(shakaAssets.Feature.MP4) - .addFeature(shakaAssets.Feature.SURROUND) - .addFeature(shakaAssets.Feature.WEBM) - .addFeature(shakaAssets.Feature.OFFLINE), + .addFeature(shakaAssets.Feature.DASH) + .addFeature(shakaAssets.Feature.MP4) + .addFeature(shakaAssets.Feature.SURROUND) + .addFeature(shakaAssets.Feature.WEBM) + .addFeature(shakaAssets.Feature.OFFLINE), new ShakaDemoAssetInfo( /* name= */ 'Shaka Player History (multicodec, live, DASH)', /* iconUri= */ 'https://storage.googleapis.com/shaka-asset-icons/shaka.png', /* manifestUri= */ 'https://storage.googleapis.com/shaka-live-assets/player-source.mpd', /* source= */ shakaAssets.Source.SHAKA) - .addFeature(shakaAssets.Feature.DASH) - .addFeature(shakaAssets.Feature.HIGH_DEFINITION) - .addFeature(shakaAssets.Feature.LIVE) - .addFeature(shakaAssets.Feature.MP4) - .addFeature(shakaAssets.Feature.WEBM), + .addFeature(shakaAssets.Feature.DASH) + .addFeature(shakaAssets.Feature.HIGH_DEFINITION) + .addFeature(shakaAssets.Feature.LIVE) + .addFeature(shakaAssets.Feature.MP4) + .addFeature(shakaAssets.Feature.WEBM), new ShakaDemoAssetInfo( /* name= */ 'Shaka Player History (live, HLS)', /* iconUri= */ 'https://storage.googleapis.com/shaka-asset-icons/shaka.png', /* manifestUri= */ 'https://storage.googleapis.com/shaka-live-assets/player-source.m3u8', /* source= */ shakaAssets.Source.SHAKA) - .addDescription('A self-indulgent HLS livestream.') - .markAsFeatured('Shaka Player History') - .addFeature(shakaAssets.Feature.HIGH_DEFINITION) - .addFeature(shakaAssets.Feature.HLS) - .addFeature(shakaAssets.Feature.LIVE) - .addFeature(shakaAssets.Feature.MP4), + .addDescription('A self-indulgent HLS livestream.') + .markAsFeatured('Shaka Player History') + .addFeature(shakaAssets.Feature.HIGH_DEFINITION) + .addFeature(shakaAssets.Feature.HLS) + .addFeature(shakaAssets.Feature.LIVE) + .addFeature(shakaAssets.Feature.MP4), // }}} // Axinom assets {{{ @@ -470,107 +470,107 @@ shakaAssets.testAssets = [ /* iconUri= */ 'https://storage.googleapis.com/shaka-asset-icons/tears_of_steel.png', /* manifestUri= */ 'https://media.axprod.net/TestVectors/v7-MultiDRM-SingleKey/Manifest.mpd', /* source= */ shakaAssets.Source.AXINOM) - .addKeySystem(shakaAssets.KeySystem.PLAYREADY) - .addKeySystem(shakaAssets.KeySystem.WIDEVINE) - .addFeature(shakaAssets.Feature.DASH) - .addFeature(shakaAssets.Feature.HIGH_DEFINITION) - .addFeature(shakaAssets.Feature.MP4) - .addFeature(shakaAssets.Feature.MULTIPLE_LANGUAGES) - .addFeature(shakaAssets.Feature.SUBTITLES) - .addFeature(shakaAssets.Feature.TTML) - .addFeature(shakaAssets.Feature.ULTRA_HIGH_DEFINITION) - .addFeature(shakaAssets.Feature.WEBVTT) - .addLicenseServer('com.widevine.alpha', 'https://drm-widevine-licensing.axtest.net/AcquireLicense') - .addLicenseServer('com.microsoft.playready', 'https://drm-playready-licensing.axtest.net/AcquireLicense') - .addLicenseRequestHeader('X-AxDRM-Message', 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ2ZXJzaW9uIjoxLCJjb21fa2V5X2lkIjoiYjMzNjRlYjUtNTFmNi00YWUzLThjOTgtMzNjZWQ1ZTMxYzc4IiwibWVzc2FnZSI6eyJ0eXBlIjoiZW50aXRsZW1lbnRfbWVzc2FnZSIsImtleXMiOlt7ImlkIjoiOWViNDA1MGQtZTQ0Yi00ODAyLTkzMmUtMjdkNzUwODNlMjY2IiwiZW5jcnlwdGVkX2tleSI6ImxLM09qSExZVzI0Y3Iya3RSNzRmbnc9PSJ9XX19.4lWwW46k-oWcah8oN18LPj5OLS5ZU-_AQv7fe0JhNjA'), // eslint-disable-line max-len + .addKeySystem(shakaAssets.KeySystem.PLAYREADY) + .addKeySystem(shakaAssets.KeySystem.WIDEVINE) + .addFeature(shakaAssets.Feature.DASH) + .addFeature(shakaAssets.Feature.HIGH_DEFINITION) + .addFeature(shakaAssets.Feature.MP4) + .addFeature(shakaAssets.Feature.MULTIPLE_LANGUAGES) + .addFeature(shakaAssets.Feature.SUBTITLES) + .addFeature(shakaAssets.Feature.TTML) + .addFeature(shakaAssets.Feature.ULTRA_HIGH_DEFINITION) + .addFeature(shakaAssets.Feature.WEBVTT) + .addLicenseServer('com.widevine.alpha', 'https://drm-widevine-licensing.axtest.net/AcquireLicense') + .addLicenseServer('com.microsoft.playready', 'https://drm-playready-licensing.axtest.net/AcquireLicense') + .addLicenseRequestHeader('X-AxDRM-Message', 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ2ZXJzaW9uIjoxLCJjb21fa2V5X2lkIjoiYjMzNjRlYjUtNTFmNi00YWUzLThjOTgtMzNjZWQ1ZTMxYzc4IiwibWVzc2FnZSI6eyJ0eXBlIjoiZW50aXRsZW1lbnRfbWVzc2FnZSIsImtleXMiOlt7ImlkIjoiOWViNDA1MGQtZTQ0Yi00ODAyLTkzMmUtMjdkNzUwODNlMjY2IiwiZW5jcnlwdGVkX2tleSI6ImxLM09qSExZVzI0Y3Iya3RSNzRmbnc9PSJ9XX19.4lWwW46k-oWcah8oN18LPj5OLS5ZU-_AQv7fe0JhNjA'), // eslint-disable-line max-len new ShakaDemoAssetInfo( /* name= */ 'Multi-DRM, multi-key', /* iconUri= */ 'https://storage.googleapis.com/shaka-asset-icons/tears_of_steel.png', /* manifestUri= */ 'https://media.axprod.net/TestVectors/v7-MultiDRM-MultiKey/Manifest.mpd', /* source= */ shakaAssets.Source.AXINOM) - .addKeySystem(shakaAssets.KeySystem.PLAYREADY) - .addKeySystem(shakaAssets.KeySystem.WIDEVINE) - .addFeature(shakaAssets.Feature.DASH) - .addFeature(shakaAssets.Feature.HIGH_DEFINITION) - .addFeature(shakaAssets.Feature.MP4) - .addFeature(shakaAssets.Feature.MULTIPLE_LANGUAGES) - .addFeature(shakaAssets.Feature.MULTIKEY) - .addFeature(shakaAssets.Feature.SUBTITLES) - .addFeature(shakaAssets.Feature.TTML) - .addFeature(shakaAssets.Feature.ULTRA_HIGH_DEFINITION) - .addFeature(shakaAssets.Feature.WEBVTT) - .addLicenseServer('com.widevine.alpha', 'https://drm-widevine-licensing.axtest.net/AcquireLicense') - .addLicenseServer('com.microsoft.playready', 'https://drm-playready-licensing.axtest.net/AcquireLicense') - .addLicenseRequestHeader('X-AxDRM-Message', 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ2ZXJzaW9uIjoxLCJjb21fa2V5X2lkIjoiYjMzNjRlYjUtNTFmNi00YWUzLThjOTgtMzNjZWQ1ZTMxYzc4IiwibWVzc2FnZSI6eyJ0eXBlIjoiZW50aXRsZW1lbnRfbWVzc2FnZSIsImtleXMiOlt7ImlkIjoiODAzOTliZjUtOGEyMS00MDE0LTgwNTMtZTI3ZTc0OGU5OGMwIiwiZW5jcnlwdGVkX2tleSI6ImxpTkpxVmFZa05oK01LY3hKRms3SWc9PSJ9LHsiaWQiOiI5MDk1M2UwOS02Y2IyLTQ5YTMtYTI2MC03YTVmZWZlYWQ0OTkiLCJlbmNyeXB0ZWRfa2V5Ijoia1l0SEh2cnJmQ01lVmRKNkxrYmtuZz09In0seyJpZCI6IjBlNGRhOTJiLWQwZTgtNGE2Ni04YzNmLWMyNWE5N2ViNjUzMiIsImVuY3J5cHRlZF9rZXkiOiI3dzdOWkhITE1nSjRtUUtFSzVMVE1RPT0ifSx7ImlkIjoiNTg1ZjIzM2YtMzA3Mi00NmYxLTlmYTQtNmRjMjJjNjZhMDE0IiwiZW5jcnlwdGVkX2tleSI6IkFjNFVVbVl0Qko1blBROU4xNXJjM2c9PSJ9LHsiaWQiOiI0MjIyYmQ3OC1iYzQ1LTQxYmYtYjYzZS02ZjgxNGRjMzkxZGYiLCJlbmNyeXB0ZWRfa2V5IjoiTzZGTzBmcVNXb3BwN2JqYy9ENGxNQT09In1dfX0.uF6YlKAREOmbniAeYiH070HSJhV0YS7zSKjlCtiDR5Y'), // eslint-disable-line max-len + .addKeySystem(shakaAssets.KeySystem.PLAYREADY) + .addKeySystem(shakaAssets.KeySystem.WIDEVINE) + .addFeature(shakaAssets.Feature.DASH) + .addFeature(shakaAssets.Feature.HIGH_DEFINITION) + .addFeature(shakaAssets.Feature.MP4) + .addFeature(shakaAssets.Feature.MULTIPLE_LANGUAGES) + .addFeature(shakaAssets.Feature.MULTIKEY) + .addFeature(shakaAssets.Feature.SUBTITLES) + .addFeature(shakaAssets.Feature.TTML) + .addFeature(shakaAssets.Feature.ULTRA_HIGH_DEFINITION) + .addFeature(shakaAssets.Feature.WEBVTT) + .addLicenseServer('com.widevine.alpha', 'https://drm-widevine-licensing.axtest.net/AcquireLicense') + .addLicenseServer('com.microsoft.playready', 'https://drm-playready-licensing.axtest.net/AcquireLicense') + .addLicenseRequestHeader('X-AxDRM-Message', 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ2ZXJzaW9uIjoxLCJjb21fa2V5X2lkIjoiYjMzNjRlYjUtNTFmNi00YWUzLThjOTgtMzNjZWQ1ZTMxYzc4IiwibWVzc2FnZSI6eyJ0eXBlIjoiZW50aXRsZW1lbnRfbWVzc2FnZSIsImtleXMiOlt7ImlkIjoiODAzOTliZjUtOGEyMS00MDE0LTgwNTMtZTI3ZTc0OGU5OGMwIiwiZW5jcnlwdGVkX2tleSI6ImxpTkpxVmFZa05oK01LY3hKRms3SWc9PSJ9LHsiaWQiOiI5MDk1M2UwOS02Y2IyLTQ5YTMtYTI2MC03YTVmZWZlYWQ0OTkiLCJlbmNyeXB0ZWRfa2V5Ijoia1l0SEh2cnJmQ01lVmRKNkxrYmtuZz09In0seyJpZCI6IjBlNGRhOTJiLWQwZTgtNGE2Ni04YzNmLWMyNWE5N2ViNjUzMiIsImVuY3J5cHRlZF9rZXkiOiI3dzdOWkhITE1nSjRtUUtFSzVMVE1RPT0ifSx7ImlkIjoiNTg1ZjIzM2YtMzA3Mi00NmYxLTlmYTQtNmRjMjJjNjZhMDE0IiwiZW5jcnlwdGVkX2tleSI6IkFjNFVVbVl0Qko1blBROU4xNXJjM2c9PSJ9LHsiaWQiOiI0MjIyYmQ3OC1iYzQ1LTQxYmYtYjYzZS02ZjgxNGRjMzkxZGYiLCJlbmNyeXB0ZWRfa2V5IjoiTzZGTzBmcVNXb3BwN2JqYy9ENGxNQT09In1dfX0.uF6YlKAREOmbniAeYiH070HSJhV0YS7zSKjlCtiDR5Y'), // eslint-disable-line max-len new ShakaDemoAssetInfo( /* name= */ 'Multi-DRM, multi-key, multi-Period', /* iconUri= */ 'https://storage.googleapis.com/shaka-asset-icons/tears_of_steel.png', /* manifestUri= */ 'https://media.axprod.net/TestVectors/v7-MultiDRM-MultiKey-MultiPeriod/Manifest.mpd', /* source= */ shakaAssets.Source.AXINOM) - .addKeySystem(shakaAssets.KeySystem.PLAYREADY) - .addKeySystem(shakaAssets.KeySystem.WIDEVINE) - .addFeature(shakaAssets.Feature.DASH) - .addFeature(shakaAssets.Feature.HIGH_DEFINITION) - .addFeature(shakaAssets.Feature.MP4) - .addFeature(shakaAssets.Feature.MULTIPLE_LANGUAGES) - .addFeature(shakaAssets.Feature.SUBTITLES) - .addFeature(shakaAssets.Feature.MULTIKEY) - .addFeature(shakaAssets.Feature.MULTIPERIOD) - .addFeature(shakaAssets.Feature.TTML) - .addFeature(shakaAssets.Feature.ULTRA_HIGH_DEFINITION) - .addFeature(shakaAssets.Feature.WEBVTT) - .addLicenseServer('com.widevine.alpha', 'https://drm-widevine-licensing.axtest.net/AcquireLicense') - .addLicenseServer('com.microsoft.playready', 'https://drm-playready-licensing.axtest.net/AcquireLicense') - .addLicenseRequestHeader('X-AxDRM-Message', 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ2ZXJzaW9uIjoxLCJjb21fa2V5X2lkIjoiYjMzNjRlYjUtNTFmNi00YWUzLThjOTgtMzNjZWQ1ZTMxYzc4IiwibWVzc2FnZSI6eyJ0eXBlIjoiZW50aXRsZW1lbnRfbWVzc2FnZSIsImtleXMiOlt7ImlkIjoiMDg3Mjc4NmUtZjllNy00NjVmLWEzYTItNGU1YjBlZjhmYTQ1IiwiZW5jcnlwdGVkX2tleSI6IlB3NitlRVlOY3ZqWWJmc2gzWDNmbWc9PSJ9LHsiaWQiOiJjMTRmMDcwOS1mMmI5LTQ0MjctOTE2Yi02MWI1MjU4NjUwNmEiLCJlbmNyeXB0ZWRfa2V5IjoiLzErZk5paDM4bXFSdjR5Y1l6bnQvdz09In0seyJpZCI6IjhiMDI5ZTUxLWQ1NmEtNDRiZC05MTBmLWQ0YjVmZDkwZmJhMiIsImVuY3J5cHRlZF9rZXkiOiJrcTBKdVpFanBGTjhzYVRtdDU2ME9nPT0ifSx7ImlkIjoiMmQ2ZTkzODctNjBjYS00MTQ1LWFlYzItYzQwODM3YjRiMDI2IiwiZW5jcnlwdGVkX2tleSI6IlRjUlFlQld4RW9IT0tIcmFkNFNlVlE9PSJ9LHsiaWQiOiJkZTAyZjA3Zi1hMDk4LTRlZTAtYjU1Ni05MDdjMGQxN2ZiYmMiLCJlbmNyeXB0ZWRfa2V5IjoicG9lbmNTN0dnbWVHRmVvSjZQRUFUUT09In0seyJpZCI6IjkxNGU2OWY0LTBhYjMtNDUzNC05ZTlmLTk4NTM2MTVlMjZmNiIsImVuY3J5cHRlZF9rZXkiOiJlaUkvTXNsbHJRNHdDbFJUL0xObUNBPT0ifSx7ImlkIjoiZGE0NDQ1YzItZGI1ZS00OGVmLWIwOTYtM2VmMzQ3YjE2YzdmIiwiZW5jcnlwdGVkX2tleSI6IjJ3K3pkdnFycERWM3hSMGJKeTR1Z3c9PSJ9LHsiaWQiOiIyOWYwNWU4Zi1hMWFlLTQ2ZTQtODBlOS0yMmRjZDQ0Y2Q3YTEiLCJlbmNyeXB0ZWRfa2V5IjoiL3hsU0hweHdxdTNnby9nbHBtU2dhUT09In0seyJpZCI6IjY5ZmU3MDc3LWRhZGQtNGI1NS05NmNkLWMzZWRiMzk5MTg1MyIsImVuY3J5cHRlZF9rZXkiOiJ6dTZpdXpOMnBzaTBaU3hRaUFUa1JRPT0ifV19fQ.BXr93Et1krYMVs-CUnf7F3ywJWFRtxYdkR7Qn4w3-to'), // eslint-disable-line max-len + .addKeySystem(shakaAssets.KeySystem.PLAYREADY) + .addKeySystem(shakaAssets.KeySystem.WIDEVINE) + .addFeature(shakaAssets.Feature.DASH) + .addFeature(shakaAssets.Feature.HIGH_DEFINITION) + .addFeature(shakaAssets.Feature.MP4) + .addFeature(shakaAssets.Feature.MULTIPLE_LANGUAGES) + .addFeature(shakaAssets.Feature.SUBTITLES) + .addFeature(shakaAssets.Feature.MULTIKEY) + .addFeature(shakaAssets.Feature.MULTIPERIOD) + .addFeature(shakaAssets.Feature.TTML) + .addFeature(shakaAssets.Feature.ULTRA_HIGH_DEFINITION) + .addFeature(shakaAssets.Feature.WEBVTT) + .addLicenseServer('com.widevine.alpha', 'https://drm-widevine-licensing.axtest.net/AcquireLicense') + .addLicenseServer('com.microsoft.playready', 'https://drm-playready-licensing.axtest.net/AcquireLicense') + .addLicenseRequestHeader('X-AxDRM-Message', 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ2ZXJzaW9uIjoxLCJjb21fa2V5X2lkIjoiYjMzNjRlYjUtNTFmNi00YWUzLThjOTgtMzNjZWQ1ZTMxYzc4IiwibWVzc2FnZSI6eyJ0eXBlIjoiZW50aXRsZW1lbnRfbWVzc2FnZSIsImtleXMiOlt7ImlkIjoiMDg3Mjc4NmUtZjllNy00NjVmLWEzYTItNGU1YjBlZjhmYTQ1IiwiZW5jcnlwdGVkX2tleSI6IlB3NitlRVlOY3ZqWWJmc2gzWDNmbWc9PSJ9LHsiaWQiOiJjMTRmMDcwOS1mMmI5LTQ0MjctOTE2Yi02MWI1MjU4NjUwNmEiLCJlbmNyeXB0ZWRfa2V5IjoiLzErZk5paDM4bXFSdjR5Y1l6bnQvdz09In0seyJpZCI6IjhiMDI5ZTUxLWQ1NmEtNDRiZC05MTBmLWQ0YjVmZDkwZmJhMiIsImVuY3J5cHRlZF9rZXkiOiJrcTBKdVpFanBGTjhzYVRtdDU2ME9nPT0ifSx7ImlkIjoiMmQ2ZTkzODctNjBjYS00MTQ1LWFlYzItYzQwODM3YjRiMDI2IiwiZW5jcnlwdGVkX2tleSI6IlRjUlFlQld4RW9IT0tIcmFkNFNlVlE9PSJ9LHsiaWQiOiJkZTAyZjA3Zi1hMDk4LTRlZTAtYjU1Ni05MDdjMGQxN2ZiYmMiLCJlbmNyeXB0ZWRfa2V5IjoicG9lbmNTN0dnbWVHRmVvSjZQRUFUUT09In0seyJpZCI6IjkxNGU2OWY0LTBhYjMtNDUzNC05ZTlmLTk4NTM2MTVlMjZmNiIsImVuY3J5cHRlZF9rZXkiOiJlaUkvTXNsbHJRNHdDbFJUL0xObUNBPT0ifSx7ImlkIjoiZGE0NDQ1YzItZGI1ZS00OGVmLWIwOTYtM2VmMzQ3YjE2YzdmIiwiZW5jcnlwdGVkX2tleSI6IjJ3K3pkdnFycERWM3hSMGJKeTR1Z3c9PSJ9LHsiaWQiOiIyOWYwNWU4Zi1hMWFlLTQ2ZTQtODBlOS0yMmRjZDQ0Y2Q3YTEiLCJlbmNyeXB0ZWRfa2V5IjoiL3hsU0hweHdxdTNnby9nbHBtU2dhUT09In0seyJpZCI6IjY5ZmU3MDc3LWRhZGQtNGI1NS05NmNkLWMzZWRiMzk5MTg1MyIsImVuY3J5cHRlZF9rZXkiOiJ6dTZpdXpOMnBzaTBaU3hRaUFUa1JRPT0ifV19fQ.BXr93Et1krYMVs-CUnf7F3ywJWFRtxYdkR7Qn4w3-to'), // eslint-disable-line max-len new ShakaDemoAssetInfo( /* name= */ 'Clear, single-Period', /* iconUri= */ 'https://storage.googleapis.com/shaka-asset-icons/tears_of_steel.png', /* manifestUri= */ 'https://media.axprod.net/TestVectors/v7-Clear/Manifest.mpd', /* source= */ shakaAssets.Source.AXINOM) - .addFeature(shakaAssets.Feature.DASH) - .addFeature(shakaAssets.Feature.HIGH_DEFINITION) - .addFeature(shakaAssets.Feature.MP4) - .addFeature(shakaAssets.Feature.MULTIPLE_LANGUAGES) - .addFeature(shakaAssets.Feature.TTML) - .addFeature(shakaAssets.Feature.SUBTITLES) - .addFeature(shakaAssets.Feature.ULTRA_HIGH_DEFINITION) - .addFeature(shakaAssets.Feature.WEBVTT) - .addFeature(shakaAssets.Feature.OFFLINE), + .addFeature(shakaAssets.Feature.DASH) + .addFeature(shakaAssets.Feature.HIGH_DEFINITION) + .addFeature(shakaAssets.Feature.MP4) + .addFeature(shakaAssets.Feature.MULTIPLE_LANGUAGES) + .addFeature(shakaAssets.Feature.TTML) + .addFeature(shakaAssets.Feature.SUBTITLES) + .addFeature(shakaAssets.Feature.ULTRA_HIGH_DEFINITION) + .addFeature(shakaAssets.Feature.WEBVTT) + .addFeature(shakaAssets.Feature.OFFLINE), new ShakaDemoAssetInfo( /* name= */ 'Clear, multi-Period', /* iconUri= */ 'https://storage.googleapis.com/shaka-asset-icons/tears_of_steel.png', /* manifestUri= */ 'https://media.axprod.net/TestVectors/v7-Clear/Manifest_MultiPeriod.mpd', /* source= */ shakaAssets.Source.AXINOM) - .addFeature(shakaAssets.Feature.DASH) - .addFeature(shakaAssets.Feature.HIGH_DEFINITION) - .addFeature(shakaAssets.Feature.MP4) - .addFeature(shakaAssets.Feature.MULTIPLE_LANGUAGES) - .addFeature(shakaAssets.Feature.MULTIPERIOD) - .addFeature(shakaAssets.Feature.TTML) - .addFeature(shakaAssets.Feature.SUBTITLES) - .addFeature(shakaAssets.Feature.ULTRA_HIGH_DEFINITION) - .addFeature(shakaAssets.Feature.WEBVTT) - .addFeature(shakaAssets.Feature.OFFLINE), + .addFeature(shakaAssets.Feature.DASH) + .addFeature(shakaAssets.Feature.HIGH_DEFINITION) + .addFeature(shakaAssets.Feature.MP4) + .addFeature(shakaAssets.Feature.MULTIPLE_LANGUAGES) + .addFeature(shakaAssets.Feature.MULTIPERIOD) + .addFeature(shakaAssets.Feature.TTML) + .addFeature(shakaAssets.Feature.SUBTITLES) + .addFeature(shakaAssets.Feature.ULTRA_HIGH_DEFINITION) + .addFeature(shakaAssets.Feature.WEBVTT) + .addFeature(shakaAssets.Feature.OFFLINE), new ShakaDemoAssetInfo( /* name= */ 'Clear, Live DASH', /* iconUri= */ 'https://storage.googleapis.com/shaka-asset-icons/axinom_test.png', /* manifestUri= */ 'https://akamai-axtest.akamaized.net/routes/lapd-v1-acceptance/www_c4/Manifest.mpd', /* source= */ shakaAssets.Source.AXINOM) - .addFeature(shakaAssets.Feature.LIVE) - .addFeature(shakaAssets.Feature.MP4) - .addFeature(shakaAssets.Feature.DASH) - .addFeature(shakaAssets.Feature.MULTIPERIOD) - .addFeature(shakaAssets.Feature.HIGH_DEFINITION) - .addFeature(shakaAssets.Feature.WEBVTT), + .addFeature(shakaAssets.Feature.LIVE) + .addFeature(shakaAssets.Feature.MP4) + .addFeature(shakaAssets.Feature.DASH) + .addFeature(shakaAssets.Feature.MULTIPERIOD) + .addFeature(shakaAssets.Feature.HIGH_DEFINITION) + .addFeature(shakaAssets.Feature.WEBVTT), new ShakaDemoAssetInfo( /* name= */ 'Clear, Live HLS', /* iconUri= */ 'https://storage.googleapis.com/shaka-asset-icons/axinom_test.png', /* manifestUri= */ 'https://akamai-axtest.akamaized.net/routes/lapd-v1-acceptance/www_c4/Manifest.m3u8', /* source= */ shakaAssets.Source.AXINOM) - .addFeature(shakaAssets.Feature.HLS) - .addFeature(shakaAssets.Feature.LIVE) - .addFeature(shakaAssets.Feature.MP4) - .addFeature(shakaAssets.Feature.HIGH_DEFINITION), + .addFeature(shakaAssets.Feature.HLS) + .addFeature(shakaAssets.Feature.LIVE) + .addFeature(shakaAssets.Feature.MP4) + .addFeature(shakaAssets.Feature.HIGH_DEFINITION), // }}} // Unified Streaming {{{ @@ -580,45 +580,45 @@ shakaAssets.testAssets = [ /* iconUri= */ 'https://storage.googleapis.com/shaka-asset-icons/tears_of_steel.png', /* manifestUri= */ 'https://demo.unified-streaming.com/video/tears-of-steel/tears-of-steel.ism/.mpd', /* source= */ shakaAssets.Source.UNIFIED_STREAMING) - .addFeature(shakaAssets.Feature.DASH) - .addFeature(shakaAssets.Feature.HIGH_DEFINITION) - .addFeature(shakaAssets.Feature.MP4) - .addFeature(shakaAssets.Feature.OFFLINE), + .addFeature(shakaAssets.Feature.DASH) + .addFeature(shakaAssets.Feature.HIGH_DEFINITION) + .addFeature(shakaAssets.Feature.MP4) + .addFeature(shakaAssets.Feature.OFFLINE), new ShakaDemoAssetInfo( /* name= */ 'Tears of Steel (Widevine)', /* iconUri= */ 'https://storage.googleapis.com/shaka-asset-icons/tears_of_steel.png', /* manifestUri= */ 'https://demo.unified-streaming.com/video/tears-of-steel/tears-of-steel-dash-widevine.ism/.mpd', /* source= */ shakaAssets.Source.UNIFIED_STREAMING) - .addKeySystem(shakaAssets.KeySystem.WIDEVINE) - .addFeature(shakaAssets.Feature.DASH) - .addFeature(shakaAssets.Feature.HIGH_DEFINITION) - .addFeature(shakaAssets.Feature.MP4) - .addFeature(shakaAssets.Feature.SUBTITLES) - .addFeature(shakaAssets.Feature.TTML) - .addLicenseServer('com.widevine.alpha', 'https://cwip-shaka-proxy.appspot.com/no_auth'), + .addKeySystem(shakaAssets.KeySystem.WIDEVINE) + .addFeature(shakaAssets.Feature.DASH) + .addFeature(shakaAssets.Feature.HIGH_DEFINITION) + .addFeature(shakaAssets.Feature.MP4) + .addFeature(shakaAssets.Feature.SUBTITLES) + .addFeature(shakaAssets.Feature.TTML) + .addLicenseServer('com.widevine.alpha', 'https://cwip-shaka-proxy.appspot.com/no_auth'), new ShakaDemoAssetInfo( /* name= */ 'Tears of Steel (PlayReady)', /* iconUri= */ 'https://storage.googleapis.com/shaka-asset-icons/tears_of_steel.png', /* manifestUri= */ 'https://demo.unified-streaming.com/video/tears-of-steel/tears-of-steel-dash-playready.ism/.mpd', /* source= */ shakaAssets.Source.UNIFIED_STREAMING) - .addKeySystem(shakaAssets.KeySystem.PLAYREADY) - .addFeature(shakaAssets.Feature.DASH) - .addFeature(shakaAssets.Feature.HIGH_DEFINITION) - .addFeature(shakaAssets.Feature.MP4) - .addFeature(shakaAssets.Feature.SUBTITLES) - .addFeature(shakaAssets.Feature.TTML) - .addLicenseServer('com.microsoft.playready', 'https://test.playready.microsoft.com/service/rightsmanager.asmx?PlayRight=1&UseSimpleNonPersistentLicense=1'), + .addKeySystem(shakaAssets.KeySystem.PLAYREADY) + .addFeature(shakaAssets.Feature.DASH) + .addFeature(shakaAssets.Feature.HIGH_DEFINITION) + .addFeature(shakaAssets.Feature.MP4) + .addFeature(shakaAssets.Feature.SUBTITLES) + .addFeature(shakaAssets.Feature.TTML) + .addLicenseServer('com.microsoft.playready', 'https://test.playready.microsoft.com/service/rightsmanager.asmx?PlayRight=1&UseSimpleNonPersistentLicense=1'), new ShakaDemoAssetInfo( /* name= */ 'Tears of Steel (subtitles)', /* iconUri= */ 'https://storage.googleapis.com/shaka-asset-icons/tears_of_steel.png', /* manifestUri= */ 'https://demo.unified-streaming.com/video/tears-of-steel/tears-of-steel-en.ism/.mpd', /* source= */ shakaAssets.Source.UNIFIED_STREAMING) - .addFeature(shakaAssets.Feature.DASH) - .addFeature(shakaAssets.Feature.HIGH_DEFINITION) - .addFeature(shakaAssets.Feature.MP4) - .addFeature(shakaAssets.Feature.SUBTITLES) - .addFeature(shakaAssets.Feature.TTML) - .addFeature(shakaAssets.Feature.OFFLINE), + .addFeature(shakaAssets.Feature.DASH) + .addFeature(shakaAssets.Feature.HIGH_DEFINITION) + .addFeature(shakaAssets.Feature.MP4) + .addFeature(shakaAssets.Feature.SUBTITLES) + .addFeature(shakaAssets.Feature.TTML) + .addFeature(shakaAssets.Feature.OFFLINE), // }}} // DASH-IF assets {{{ @@ -628,66 +628,66 @@ shakaAssets.testAssets = [ /* iconUri= */ 'https://storage.googleapis.com/shaka-asset-icons/big_buck_bunny.png', /* manifestUri= */ 'https://dash.akamaized.net/dash264/TestCases/1c/qualcomm/2/MultiRate.mpd', /* source= */ shakaAssets.Source.DASH_IF) - .addFeature(shakaAssets.Feature.MP4) - .addFeature(shakaAssets.Feature.DASH) - .addFeature(shakaAssets.Feature.HIGH_DEFINITION) - .addFeature(shakaAssets.Feature.OFFLINE), + .addFeature(shakaAssets.Feature.MP4) + .addFeature(shakaAssets.Feature.DASH) + .addFeature(shakaAssets.Feature.HIGH_DEFINITION) + .addFeature(shakaAssets.Feature.OFFLINE), new ShakaDemoAssetInfo( /* name= */ 'Live sim (2s segments)', /* iconUri= */ 'https://storage.googleapis.com/shaka-asset-icons/dash_if_test_pattern.png', /* manifestUri= */ 'https://livesim.dashif.org/livesim/utc_head/testpic_2s/Manifest.mpd', /* source= */ shakaAssets.Source.DASH_IF) - .addFeature(shakaAssets.Feature.LIVE) - .addFeature(shakaAssets.Feature.MP4) - .addFeature(shakaAssets.Feature.DASH), + .addFeature(shakaAssets.Feature.LIVE) + .addFeature(shakaAssets.Feature.MP4) + .addFeature(shakaAssets.Feature.DASH), new ShakaDemoAssetInfo( /* name= */ 'Live sim SegmentTimeline w $Time$ (6s segments)', /* iconUri= */ 'https://storage.googleapis.com/shaka-asset-icons/dash_if_test_pattern.png', /* manifestUri= */ 'https://livesim.dashif.org/livesim/segtimeline_1/utc_head/testpic_6s/Manifest.mpd', /* source= */ shakaAssets.Source.DASH_IF) - .addFeature(shakaAssets.Feature.DASH) - .addFeature(shakaAssets.Feature.LIVE) - .addFeature(shakaAssets.Feature.MP4), + .addFeature(shakaAssets.Feature.DASH) + .addFeature(shakaAssets.Feature.LIVE) + .addFeature(shakaAssets.Feature.MP4), new ShakaDemoAssetInfo( /* name= */ 'Live sim SegmentTimeline w $Number$ (6s segments)', /* iconUri= */ 'https://storage.googleapis.com/shaka-asset-icons/dash_if_test_pattern.png', /* manifestUri= */ 'https://livesim.dashif.org/livesim/segtimelinenr_1/utc_head/testpic_6s/Manifest.mpd', /* source= */ shakaAssets.Source.DASH_IF) - .addFeature(shakaAssets.Feature.DASH) - .addFeature(shakaAssets.Feature.LIVE) - .addFeature(shakaAssets.Feature.MP4), + .addFeature(shakaAssets.Feature.DASH) + .addFeature(shakaAssets.Feature.LIVE) + .addFeature(shakaAssets.Feature.MP4), new ShakaDemoAssetInfo( /* name= */ 'Live sim SegmentTimeline StartOver [-20s, +20s] (2s segments)', // eslint-disable-line max-len /* iconUri= */ 'https://storage.googleapis.com/shaka-asset-icons/dash_if_test_pattern.png', /* manifestUri= */ 'https://livesim.dashif.org/livesim/segtimeline_1/startrel_-20/stoprel_20/timeoffset_0/testpic_2s/Manifest.mpd', /* source= */ shakaAssets.Source.DASH_IF) - .addFeature(shakaAssets.Feature.DASH) - .addFeature(shakaAssets.Feature.MP4), + .addFeature(shakaAssets.Feature.DASH) + .addFeature(shakaAssets.Feature.MP4), new ShakaDemoAssetInfo( /* name= */ 'Live sim StartOver SegTmpl Duration [-20s, +20s] (2s segments)', // eslint-disable-line max-len /* iconUri= */ 'https://storage.googleapis.com/shaka-asset-icons/dash_if_test_pattern.png', /* manifestUri= */ 'https://livesim.dashif.org/livesim/startrel_-20/stoprel_20/timeoffset_0/testpic_2s/Manifest.mpd', /* source= */ shakaAssets.Source.DASH_IF) - .addFeature(shakaAssets.Feature.DASH) - .addFeature(shakaAssets.Feature.MP4), + .addFeature(shakaAssets.Feature.DASH) + .addFeature(shakaAssets.Feature.MP4), new ShakaDemoAssetInfo( /* name= */ 'Live sim SegTmpl Duration (multi-period 60s)', /* iconUri= */ 'https://storage.googleapis.com/shaka-asset-icons/dash_if_test_pattern.png', /* manifestUri= */ 'https://livesim.dashif.org/livesim/utc_head/periods_60/testpic_2s/Manifest.mpd', /* source= */ shakaAssets.Source.DASH_IF) - .addFeature(shakaAssets.Feature.DASH) - .addFeature(shakaAssets.Feature.LIVE) - .addFeature(shakaAssets.Feature.MP4) - .addFeature(shakaAssets.Feature.MULTIPERIOD), + .addFeature(shakaAssets.Feature.DASH) + .addFeature(shakaAssets.Feature.LIVE) + .addFeature(shakaAssets.Feature.MP4) + .addFeature(shakaAssets.Feature.MULTIPERIOD), new ShakaDemoAssetInfo( /* name= */ 'Live sim TTML Image Subtitles embedded (VoD)', /* iconUri= */ 'https://storage.googleapis.com/shaka-asset-icons/dash_if_test_pattern.png', /* manifestUri= */ 'https://livesim.dashif.org/dash/vod/testpic_2s/img_subs.mpd', /* source= */ shakaAssets.Source.DASH_IF) - .addFeature(shakaAssets.Feature.DASH) - .addFeature(shakaAssets.Feature.SUBTITLES) - .addFeature(shakaAssets.Feature.MP4) - .addFeature(shakaAssets.Feature.TTML), + .addFeature(shakaAssets.Feature.DASH) + .addFeature(shakaAssets.Feature.SUBTITLES) + .addFeature(shakaAssets.Feature.MP4) + .addFeature(shakaAssets.Feature.TTML), // }}} // Wowza assets {{{ @@ -697,9 +697,9 @@ shakaAssets.testAssets = [ /* iconUri= */ 'https://storage.googleapis.com/shaka-asset-icons/big_buck_bunny.png', /* manifestUri= */ 'https://wowzaec2demo.streamlock.net/live/bigbuckbunny/manifest_mpm4sav_mvtime.mpd', /* source= */ shakaAssets.Source.WOWZA) - .addFeature(shakaAssets.Feature.DASH) - .addFeature(shakaAssets.Feature.LIVE) - .addFeature(shakaAssets.Feature.MP4), + .addFeature(shakaAssets.Feature.DASH) + .addFeature(shakaAssets.Feature.LIVE) + .addFeature(shakaAssets.Feature.MP4), // }}} // bitcodin assets {{{ @@ -710,30 +710,30 @@ shakaAssets.testAssets = [ /* iconUri= */ 'https://storage.googleapis.com/shaka-asset-icons/art_of_motion.png', /* manifestUri= */ 'https://bitdash-a.akamaihd.net/content/MI201109210084_1/mpds/f08e80da-bf1d-4e3d-8899-f0f6155f6efa.mpd', /* source= */ shakaAssets.Source.BITCODIN) - .addFeature(shakaAssets.Feature.DASH) - .addFeature(shakaAssets.Feature.HIGH_DEFINITION) - .addFeature(shakaAssets.Feature.MP4) - .addFeature(shakaAssets.Feature.OFFLINE), + .addFeature(shakaAssets.Feature.DASH) + .addFeature(shakaAssets.Feature.HIGH_DEFINITION) + .addFeature(shakaAssets.Feature.MP4) + .addFeature(shakaAssets.Feature.OFFLINE), new ShakaDemoAssetInfo( /* name= */ 'Art of Motion (HLS, TS)', /* iconUri= */ 'https://storage.googleapis.com/shaka-asset-icons/art_of_motion.png', /* manifestUri= */ 'https://bitdash-a.akamaihd.net/content/MI201109210084_1/m3u8s/f08e80da-bf1d-4e3d-8899-f0f6155f6efa.m3u8', /* source= */ shakaAssets.Source.BITCODIN) - .markAsDisabled() - .addFeature(shakaAssets.Feature.HIGH_DEFINITION) - .addFeature(shakaAssets.Feature.HLS) - .addFeature(shakaAssets.Feature.MP2TS) - .addFeature(shakaAssets.Feature.OFFLINE), + .markAsDisabled() + .addFeature(shakaAssets.Feature.HIGH_DEFINITION) + .addFeature(shakaAssets.Feature.HLS) + .addFeature(shakaAssets.Feature.MP2TS) + .addFeature(shakaAssets.Feature.OFFLINE), new ShakaDemoAssetInfo( /* name= */ 'Sintel (HLS, TS, 4k)', /* iconUri= */ 'https://storage.googleapis.com/shaka-asset-icons/sintel.png', /* manifestUri= */ 'https://bitdash-a.akamaihd.net/content/sintel/hls/playlist.m3u8', /* source= */ shakaAssets.Source.BITCODIN) - .markAsDisabled() - .addFeature(shakaAssets.Feature.HIGH_DEFINITION) - .addFeature(shakaAssets.Feature.HLS) - .addFeature(shakaAssets.Feature.MP2TS) - .addFeature(shakaAssets.Feature.OFFLINE), + .markAsDisabled() + .addFeature(shakaAssets.Feature.HIGH_DEFINITION) + .addFeature(shakaAssets.Feature.HLS) + .addFeature(shakaAssets.Feature.MP2TS) + .addFeature(shakaAssets.Feature.OFFLINE), // }}} // Nimble Streamer assets {{{ @@ -745,10 +745,10 @@ shakaAssets.testAssets = [ /* iconUri= */ 'https://storage.googleapis.com/shaka-asset-icons/big_buck_bunny.png', /* manifestUri= */ 'https://video.wmspanel.com/local/raw/BigBuckBunny_320x180.mp4/manifest.mpd', /* source= */ shakaAssets.Source.NIMBLE_STREAMER) - .markAsDisabled() - .addFeature(shakaAssets.Feature.DASH) - .addFeature(shakaAssets.Feature.MP4) - .addFeature(shakaAssets.Feature.HIGH_DEFINITION), + .markAsDisabled() + .addFeature(shakaAssets.Feature.DASH) + .addFeature(shakaAssets.Feature.MP4) + .addFeature(shakaAssets.Feature.HIGH_DEFINITION), // }}} // Azure Media Services assets {{{ @@ -758,49 +758,49 @@ shakaAssets.testAssets = [ /* iconUri= */ 'https://storage.googleapis.com/shaka-asset-icons/azure.png', /* manifestUri= */ 'https://amssamples.streaming.mediaservices.windows.net/91492735-c523-432b-ba01-faba6c2206a2/AzureMediaServicesPromo.ism/manifest(format=mpd-time-csf)', /* source= */ shakaAssets.Source.AZURE_MEDIA_SERVICES) - .addFeature(shakaAssets.Feature.DASH) - .addFeature(shakaAssets.Feature.MP4) - .addFeature(shakaAssets.Feature.HIGH_DEFINITION) - .addFeature(shakaAssets.Feature.OFFLINE), + .addFeature(shakaAssets.Feature.DASH) + .addFeature(shakaAssets.Feature.MP4) + .addFeature(shakaAssets.Feature.HIGH_DEFINITION) + .addFeature(shakaAssets.Feature.OFFLINE), new ShakaDemoAssetInfo( /* name= */ 'Big Buck Bunny (Azure)', /* iconUri= */ 'https://storage.googleapis.com/shaka-asset-icons/big_buck_bunny.png', /* manifestUri= */ 'https://amssamples.streaming.mediaservices.windows.net/622b189f-ec39-43f2-93a2-201ac4e31ce1/BigBuckBunny.ism/manifest(format=mpd-time-csf)', /* source= */ shakaAssets.Source.AZURE_MEDIA_SERVICES) - .addKeySystem(shakaAssets.KeySystem.PLAYREADY) - .addKeySystem(shakaAssets.KeySystem.WIDEVINE) - .addFeature(shakaAssets.Feature.DASH) - .addFeature(shakaAssets.Feature.HIGH_DEFINITION) - .addFeature(shakaAssets.Feature.MP4) - .addFeature(shakaAssets.Feature.OFFLINE) - .addLicenseServer('com.widevine.alpha', 'https://amssamples.keydelivery.mediaservices.windows.net/Widevine/?KID=1ab45440-532c-4399-94dc-5c5ad9584bac') - .addLicenseServer('com.microsoft.playready', 'https://amssamples.keydelivery.mediaservices.windows.net/PlayReady/'), + .addKeySystem(shakaAssets.KeySystem.PLAYREADY) + .addKeySystem(shakaAssets.KeySystem.WIDEVINE) + .addFeature(shakaAssets.Feature.DASH) + .addFeature(shakaAssets.Feature.HIGH_DEFINITION) + .addFeature(shakaAssets.Feature.MP4) + .addFeature(shakaAssets.Feature.OFFLINE) + .addLicenseServer('com.widevine.alpha', 'https://amssamples.keydelivery.mediaservices.windows.net/Widevine/?KID=1ab45440-532c-4399-94dc-5c5ad9584bac') + .addLicenseServer('com.microsoft.playready', 'https://amssamples.keydelivery.mediaservices.windows.net/PlayReady/'), new ShakaDemoAssetInfo( /* name= */ 'Tears of Steel (external text)', /* iconUri= */ 'https://storage.googleapis.com/shaka-asset-icons/tears_of_steel.png', /* manifestUri= */ 'https://ams-samplescdn.streaming.mediaservices.windows.net/11196e3d-2f40-4835-9a4d-fc52751b0323/TearsOfSteel_WAMEH264SmoothStreaming720p.ism/manifest(format=mpd-time-csf)', /* source= */ shakaAssets.Source.AZURE_MEDIA_SERVICES) - .addFeature(shakaAssets.Feature.DASH) - .addFeature(shakaAssets.Feature.MP4) - .addFeature(shakaAssets.Feature.SUBTITLES) - .addFeature(shakaAssets.Feature.WEBVTT) - .addFeature(shakaAssets.Feature.OFFLINE) - .addExtraText({ - uri: 'https://ams-samplescdn.streaming.mediaservices.windows.net/11196e3d-2f40-4835-9a4d-fc52751b0323/TOS-en.vtt', - language: 'en', - kind: 'subtitle', - mime: 'text/vtt', - }).addExtraText({ - uri: 'https://ams-samplescdn.streaming.mediaservices.windows.net/11196e3d-2f40-4835-9a4d-fc52751b0323/TOS-es.vtt', - language: 'es', - kind: 'subtitle', - mime: 'text/vtt', - }).addExtraText({ - uri: 'https://ams-samplescdn.streaming.mediaservices.windows.net/11196e3d-2f40-4835-9a4d-fc52751b0323/TOS-fr.vtt', - language: 'fr', - kind: 'subtitle', - mime: 'text/vtt', - }), + .addFeature(shakaAssets.Feature.DASH) + .addFeature(shakaAssets.Feature.MP4) + .addFeature(shakaAssets.Feature.SUBTITLES) + .addFeature(shakaAssets.Feature.WEBVTT) + .addFeature(shakaAssets.Feature.OFFLINE) + .addExtraText({ + uri: 'https://ams-samplescdn.streaming.mediaservices.windows.net/11196e3d-2f40-4835-9a4d-fc52751b0323/TOS-en.vtt', + language: 'en', + kind: 'subtitle', + mime: 'text/vtt', + }).addExtraText({ + uri: 'https://ams-samplescdn.streaming.mediaservices.windows.net/11196e3d-2f40-4835-9a4d-fc52751b0323/TOS-es.vtt', + language: 'es', + kind: 'subtitle', + mime: 'text/vtt', + }).addExtraText({ + uri: 'https://ams-samplescdn.streaming.mediaservices.windows.net/11196e3d-2f40-4835-9a4d-fc52751b0323/TOS-fr.vtt', + language: 'fr', + kind: 'subtitle', + mime: 'text/vtt', + }), // }}} // GPAC assets {{{ @@ -818,28 +818,28 @@ shakaAssets.testAssets = [ /* iconUri= */ 'https://storage.googleapis.com/shaka-asset-icons/sintel.png', /* manifestUri= */ 'https://download.tsi.telecom-paristech.fr/gpac/DASH_CONFORMANCE/TelecomParisTech/mp4-live/mp4-live-mpd-AV-BS.mpd', /* source= */ shakaAssets.Source.GPAC) - .markAsDisabled() - .addFeature(shakaAssets.Feature.DASH) - .addFeature(shakaAssets.Feature.MP4), + .markAsDisabled() + .addFeature(shakaAssets.Feature.DASH) + .addFeature(shakaAssets.Feature.MP4), new ShakaDemoAssetInfo( /* name= */ 'live profile with five periods', /* iconUri= */ 'https://storage.googleapis.com/shaka-asset-icons/gpac_test_pattern.png', /* manifestUri= */ 'https://download.tsi.telecom-paristech.fr/gpac/DASH_CONFORMANCE/TelecomParisTech/mp4-live-periods/mp4-live-periods-mpd.mpd', /* source= */ shakaAssets.Source.GPAC) - .addFeature(shakaAssets.Feature.DASH) - .addFeature(shakaAssets.Feature.MP4) - .addFeature(shakaAssets.Feature.MULTIPERIOD) - .addFeature(shakaAssets.Feature.HIGH_DEFINITION) - .addFeature(shakaAssets.Feature.OFFLINE), + .addFeature(shakaAssets.Feature.DASH) + .addFeature(shakaAssets.Feature.MP4) + .addFeature(shakaAssets.Feature.MULTIPERIOD) + .addFeature(shakaAssets.Feature.HIGH_DEFINITION) + .addFeature(shakaAssets.Feature.OFFLINE), new ShakaDemoAssetInfo( /* name= */ 'main profile, single file', /* iconUri= */ 'https://storage.googleapis.com/shaka-asset-icons/gpac_test_pattern.png', /* manifestUri= */ 'https://download.tsi.telecom-paristech.fr/gpac/DASH_CONFORMANCE/TelecomParisTech/mp4-main-single/mp4-main-single-mpd-AV-NBS.mpd', /* source= */ shakaAssets.Source.GPAC) - .addFeature(shakaAssets.Feature.DASH) - .addFeature(shakaAssets.Feature.MP4) - .addFeature(shakaAssets.Feature.HIGH_DEFINITION) - .addFeature(shakaAssets.Feature.OFFLINE), + .addFeature(shakaAssets.Feature.DASH) + .addFeature(shakaAssets.Feature.MP4) + .addFeature(shakaAssets.Feature.HIGH_DEFINITION) + .addFeature(shakaAssets.Feature.OFFLINE), // NOTE: Multiple SPS/PPS in init segment, no sample duration // NOTE: Decoder errors on Mac // https://github.com/gpac/gpac/issues/600 @@ -849,18 +849,18 @@ shakaAssets.testAssets = [ /* iconUri= */ 'https://storage.googleapis.com/shaka-asset-icons/gpac_test_pattern.png', /* manifestUri= */ 'https://download.tsi.telecom-paristech.fr/gpac/DASH_CONFORMANCE/TelecomParisTech/mp4-main-multi/mp4-main-multi-mpd-AV-BS.mpd', /* source= */ shakaAssets.Source.GPAC) - .markAsDisabled() - .addFeature(shakaAssets.Feature.DASH) - .addFeature(shakaAssets.Feature.MP4), + .markAsDisabled() + .addFeature(shakaAssets.Feature.DASH) + .addFeature(shakaAssets.Feature.MP4), new ShakaDemoAssetInfo( /* name= */ 'onDemand profile', /* iconUri= */ 'https://storage.googleapis.com/shaka-asset-icons/gpac_test_pattern.png', /* manifestUri= */ 'https://download.tsi.telecom-paristech.fr/gpac/DASH_CONFORMANCE/TelecomParisTech/mp4-onDemand/mp4-onDemand-mpd-AV.mpd', /* source= */ shakaAssets.Source.GPAC) - .addFeature(shakaAssets.Feature.DASH) - .addFeature(shakaAssets.Feature.MP4) - .addFeature(shakaAssets.Feature.HIGH_DEFINITION) - .addFeature(shakaAssets.Feature.OFFLINE), + .addFeature(shakaAssets.Feature.DASH) + .addFeature(shakaAssets.Feature.MP4) + .addFeature(shakaAssets.Feature.HIGH_DEFINITION) + .addFeature(shakaAssets.Feature.OFFLINE), // NOTE: Segments do not start with keyframes // NOTE: Decoder errors on Safari // https://bugs.webkit.org/show_bug.cgi?id=160460 @@ -869,9 +869,9 @@ shakaAssets.testAssets = [ /* iconUri= */ 'https://storage.googleapis.com/shaka-asset-icons/gpac_test_pattern.png', /* manifestUri= */ 'https://download.tsi.telecom-paristech.fr/gpac/DASH_CONFORMANCE/TelecomParisTech/mp4-main-ogop/mp4-main-ogop-mpd-AV-BS.mpd', /* source= */ shakaAssets.Source.GPAC) - .markAsDisabled() - .addFeature(shakaAssets.Feature.DASH) - .addFeature(shakaAssets.Feature.MP4), + .markAsDisabled() + .addFeature(shakaAssets.Feature.DASH) + .addFeature(shakaAssets.Feature.MP4), // NOTE: segments do not start with keyframes // NOTE: Decoder errors on Safari // https://bugs.webkit.org/show_bug.cgi?id=160460 @@ -880,9 +880,9 @@ shakaAssets.testAssets = [ /* iconUri= */ 'https://storage.googleapis.com/shaka-asset-icons/gpac_test_pattern.png', /* manifestUri= */ 'https://download.tsi.telecom-paristech.fr/gpac/DASH_CONFORMANCE/TelecomParisTech/mp4-full-gdr/mp4-full-gdr-mpd-AV-BS.mpd', /* source= */ shakaAssets.Source.GPAC) - .markAsDisabled() - .addFeature(shakaAssets.Feature.DASH) - .addFeature(shakaAssets.Feature.MP4), + .markAsDisabled() + .addFeature(shakaAssets.Feature.DASH) + .addFeature(shakaAssets.Feature.MP4), // }}} // Verizon Digital Media Services (VDMS) assets {{{ @@ -893,17 +893,17 @@ shakaAssets.testAssets = [ /* iconUri= */ 'https://storage.googleapis.com/shaka-asset-icons/azure.png', /* manifestUri= */ 'https://content.uplynk.com/847859273a4b4a81959d8fea181672a4.mpd?pr.version=2&pr.playenabler=B621D91F-EDCC-4035-8D4B-DC71760D43E9&pr.securitylevel=150', /* source= */ shakaAssets.Source.UPLYNK) - .addKeySystem(shakaAssets.KeySystem.PLAYREADY) - .addKeySystem(shakaAssets.KeySystem.WIDEVINE) - .addFeature(shakaAssets.Feature.DASH) - .addFeature(shakaAssets.Feature.MP4) - .addFeature(shakaAssets.Feature.MULTIKEY) - .addFeature(shakaAssets.Feature.AESCTR_8_BYTE_IV) - .addFeature(shakaAssets.Feature.HIGH_DEFINITION) - .addLicenseServer('com.microsoft.playready', 'https://content.uplynk.com/pr') - .addLicenseServer('com.widevine.alpha', 'https://content.uplynk.com/wv') - .setRequestFilter(shakaAssets.UplynkRequestFilter) - .setResponseFilter(shakaAssets.UplynkResponseFilter), + .addKeySystem(shakaAssets.KeySystem.PLAYREADY) + .addKeySystem(shakaAssets.KeySystem.WIDEVINE) + .addFeature(shakaAssets.Feature.DASH) + .addFeature(shakaAssets.Feature.MP4) + .addFeature(shakaAssets.Feature.MULTIKEY) + .addFeature(shakaAssets.Feature.AESCTR_8_BYTE_IV) + .addFeature(shakaAssets.Feature.HIGH_DEFINITION) + .addLicenseServer('com.microsoft.playready', 'https://content.uplynk.com/pr') + .addLicenseServer('com.widevine.alpha', 'https://content.uplynk.com/wv') + .setRequestFilter(shakaAssets.UplynkRequestFilter) + .setResponseFilter(shakaAssets.UplynkResponseFilter), // Reliable Playready playback requires Edge 16+ // The playenabler and sl url parameters allow for playback in VMs new ShakaDemoAssetInfo( @@ -911,36 +911,36 @@ shakaAssets.testAssets = [ /* iconUri= */ 'https://storage.googleapis.com/shaka-asset-icons/sintel.png', /* manifestUri= */ 'https://content.uplynk.com/054225d59be2454fabdca3e96912d847.mpd?ad=cleardash&pr.version=2&pr.playenabler=B621D91F-EDCC-4035-8D4B-DC71760D43E9&pr.securitylevel=150', /* source= */ shakaAssets.Source.UPLYNK) - .addKeySystem(shakaAssets.KeySystem.PLAYREADY) - .addKeySystem(shakaAssets.KeySystem.WIDEVINE) - .addFeature(shakaAssets.Feature.DASH) - .addFeature(shakaAssets.Feature.MP4) - .addFeature(shakaAssets.Feature.SUBTITLES) - .addFeature(shakaAssets.Feature.MULTIKEY) - .addFeature(shakaAssets.Feature.MULTIPERIOD) - .addFeature(shakaAssets.Feature.WEBVTT) - .addFeature(shakaAssets.Feature.AESCTR_8_BYTE_IV) - .addFeature(shakaAssets.Feature.HIGH_DEFINITION) - .addLicenseServer('com.microsoft.playready', 'https://content.uplynk.com/pr') - .addLicenseServer('com.widevine.alpha', 'https://content.uplynk.com/wv') - .setRequestFilter(shakaAssets.UplynkRequestFilter) - .setResponseFilter(shakaAssets.UplynkResponseFilter), + .addKeySystem(shakaAssets.KeySystem.PLAYREADY) + .addKeySystem(shakaAssets.KeySystem.WIDEVINE) + .addFeature(shakaAssets.Feature.DASH) + .addFeature(shakaAssets.Feature.MP4) + .addFeature(shakaAssets.Feature.SUBTITLES) + .addFeature(shakaAssets.Feature.MULTIKEY) + .addFeature(shakaAssets.Feature.MULTIPERIOD) + .addFeature(shakaAssets.Feature.WEBVTT) + .addFeature(shakaAssets.Feature.AESCTR_8_BYTE_IV) + .addFeature(shakaAssets.Feature.HIGH_DEFINITION) + .addLicenseServer('com.microsoft.playready', 'https://content.uplynk.com/pr') + .addLicenseServer('com.widevine.alpha', 'https://content.uplynk.com/wv') + .setRequestFilter(shakaAssets.UplynkRequestFilter) + .setResponseFilter(shakaAssets.UplynkResponseFilter), new ShakaDemoAssetInfo( /* name= */ 'Widevine - 16 Byte IV', /* iconUri= */ 'https://storage.googleapis.com/shaka-asset-icons/big_buck_bunny.png', /* manifestUri= */ 'https://content.uplynk.com/224ac8717e714b68831997ab6cea4015.mpd', /* source= */ shakaAssets.Source.UPLYNK) - // Disabled until we figure out the CORS errors and PlayReady status. - .markAsDisabled() - .addKeySystem(shakaAssets.KeySystem.WIDEVINE) - .addFeature(shakaAssets.Feature.DASH) - .addFeature(shakaAssets.Feature.MP4) - .addFeature(shakaAssets.Feature.MULTIKEY) - .addFeature(shakaAssets.Feature.AESCTR_16_BYTE_IV) - .addFeature(shakaAssets.Feature.HIGH_DEFINITION) - .addLicenseServer('com.widevine.alpha', 'https://content.uplynk.com/wv') - .setRequestFilter(shakaAssets.UplynkRequestFilter) - .setResponseFilter(shakaAssets.UplynkResponseFilter), + // Disabled until we figure out the CORS errors and PlayReady status. + .markAsDisabled() + .addKeySystem(shakaAssets.KeySystem.WIDEVINE) + .addFeature(shakaAssets.Feature.DASH) + .addFeature(shakaAssets.Feature.MP4) + .addFeature(shakaAssets.Feature.MULTIKEY) + .addFeature(shakaAssets.Feature.AESCTR_16_BYTE_IV) + .addFeature(shakaAssets.Feature.HIGH_DEFINITION) + .addLicenseServer('com.widevine.alpha', 'https://content.uplynk.com/wv') + .setRequestFilter(shakaAssets.UplynkRequestFilter) + .setResponseFilter(shakaAssets.UplynkResponseFilter), // Unencrypted periods interspersed with protected periods // Doesn't work on Chrome < 58 new ShakaDemoAssetInfo( @@ -948,19 +948,19 @@ shakaAssets.testAssets = [ /* iconUri= */ 'https://storage.googleapis.com/shaka-asset-icons/sintel.png', /* manifestUri= */ 'https://content.uplynk.com/1eb40d8e64234f5c9879db7045c3d48c.mpd?ad=cleardash&rays=cdefg', /* source= */ shakaAssets.Source.UPLYNK) - // Disabled until we figure out the CORS errors and PlayReady status. - .markAsDisabled() - .addKeySystem(shakaAssets.KeySystem.WIDEVINE) - .addFeature(shakaAssets.Feature.DASH) - .addFeature(shakaAssets.Feature.MP4) - .addFeature(shakaAssets.Feature.MULTIPLE_LANGUAGES) - .addFeature(shakaAssets.Feature.MULTIPERIOD) - .addFeature(shakaAssets.Feature.MULTIKEY) - .addFeature(shakaAssets.Feature.HIGH_DEFINITION) - .addFeature(shakaAssets.Feature.AESCTR_16_BYTE_IV) - .addFeature(shakaAssets.Feature.ENCRYPTED_WITH_CLEAR) - .addLicenseServer('com.widevine.alpha', 'https://content.uplynk.com/wv') - .setRequestFilter(shakaAssets.UplynkRequestFilter) - .setResponseFilter(shakaAssets.UplynkResponseFilter), + // Disabled until we figure out the CORS errors and PlayReady status. + .markAsDisabled() + .addKeySystem(shakaAssets.KeySystem.WIDEVINE) + .addFeature(shakaAssets.Feature.DASH) + .addFeature(shakaAssets.Feature.MP4) + .addFeature(shakaAssets.Feature.MULTIPLE_LANGUAGES) + .addFeature(shakaAssets.Feature.MULTIPERIOD) + .addFeature(shakaAssets.Feature.MULTIKEY) + .addFeature(shakaAssets.Feature.HIGH_DEFINITION) + .addFeature(shakaAssets.Feature.AESCTR_16_BYTE_IV) + .addFeature(shakaAssets.Feature.ENCRYPTED_WITH_CLEAR) + .addLicenseServer('com.widevine.alpha', 'https://content.uplynk.com/wv') + .setRequestFilter(shakaAssets.UplynkRequestFilter) + .setResponseFilter(shakaAssets.UplynkResponseFilter), // }}} ]; diff --git a/demo/config.js b/demo/config.js index 35217ffda..9a8554928 100644 --- a/demo/config.js +++ b/demo/config.js @@ -120,7 +120,7 @@ class ShakaDemoConfig { const docLink = this.resolveExternLink_('.DrmConfiguration'); this.addSection_('DRM', docLink) .addBoolInput_('Delay License Request Until Played', - 'drm.delayLicenseRequestUntilPlayed'); + 'drm.delayLicenseRequestUntilPlayed'); const advanced = shakaDemoMain.getConfiguration().drm.advanced || {}; const robustnessSuggestions = [ 'SW_SECURE_CRYPTO', @@ -169,20 +169,20 @@ class ShakaDemoConfig { this.addSection_('Manifest', docLink) .addBoolInput_('Ignore DASH DRM Info', 'manifest.dash.ignoreDrmInfo') .addBoolInput_('Auto-Correct DASH Drift', - 'manifest.dash.autoCorrectDrift') + 'manifest.dash.autoCorrectDrift') .addBoolInput_('Xlink Should Fail Gracefully', - 'manifest.dash.xlinkFailGracefully') + 'manifest.dash.xlinkFailGracefully') .addNumberInput_('Availability Window Override', - 'manifest.availabilityWindowOverride', - /* canBeDecimal = */ true, - /* canBeZero = */ false, - /* canBeUnset = */ true) + 'manifest.availabilityWindowOverride', + /* canBeDecimal = */ true, + /* canBeZero = */ false, + /* canBeUnset = */ true) .addTextInput_('Clock Sync URI', 'manifest.dash.clockSyncUri') .addBoolInput_('Ignore DRM Info', 'manifest.dash.ignoreDrmInfo') .addNumberInput_('Default Presentation Delay', - 'manifest.dash.defaultPresentationDelay') + 'manifest.dash.defaultPresentationDelay') .addBoolInput_('Ignore Min Buffer Time', - 'manifest.dash.ignoreMinBufferTime'); + 'manifest.dash.ignoreMinBufferTime'); this.addRetrySection_('manifest', 'Manifest'); } @@ -193,16 +193,16 @@ class ShakaDemoConfig { this.addSection_('Adaptation', docLink) .addBoolInput_('Enabled', 'abr.enabled') .addNumberInput_('Default Bandwidth Estimate', - 'abr.defaultBandwidthEstimate') + 'abr.defaultBandwidthEstimate') .addNumberInput_('Bandwidth Downgrade Target', - 'abr.bandwidthDowngradeTarget', - /* canBeDecimal = */ true) + 'abr.bandwidthDowngradeTarget', + /* canBeDecimal = */ true) .addNumberInput_('Bandwidth Upgrade Target', - 'abr.bandwidthUpgradeTarget', - /* canBeDecimal = */ true) + 'abr.bandwidthUpgradeTarget', + /* canBeDecimal = */ true) .addNumberInput_('Switch Interval', - 'abr.switchInterval', - /* canBeDecimal = */ true); + 'abr.switchInterval', + /* canBeDecimal = */ true); this.addRetrictionsSection_('abr', 'Adaptation'); } @@ -238,17 +238,17 @@ class ShakaDemoConfig { this.addSection_(categoryName + ' Retry Parameters', docLink) .addNumberInput_('Max Attempts', prefix + 'maxAttempts') .addNumberInput_('Base Delay', - prefix + 'baseDelay', - /* canBeDecimal = */ true) + prefix + 'baseDelay', + /* canBeDecimal = */ true) .addNumberInput_('Backoff Factor', - prefix + 'backoffFactor', - /* canBeDecimal = */ true) + prefix + 'backoffFactor', + /* canBeDecimal = */ true) .addNumberInput_('Fuzz Factor', - prefix + 'fuzzFactor', - /* canBeDecimal = */ true) + prefix + 'fuzzFactor', + /* canBeDecimal = */ true) .addNumberInput_('Timeout', - prefix + 'timeout', - /* canBeDecimal = */ true); + prefix + 'timeout', + /* canBeDecimal = */ true); } /** @private */ @@ -256,7 +256,7 @@ class ShakaDemoConfig { const docLink = this.resolveExternLink_('.OfflineConfiguration'); this.addSection_('Offline', docLink) .addBoolInput_('Use Persistent Licenses', - 'offline.usePersistentLicense'); + 'offline.usePersistentLicense'); } /** @private */ @@ -264,21 +264,21 @@ class ShakaDemoConfig { const docLink = this.resolveExternLink_('.StreamingConfiguration'); this.addSection_('Streaming', docLink) .addNumberInput_('Maximum Small Gap Size', 'streaming.smallGapLimit', - /* canBeDecimal = */ true) + /* canBeDecimal = */ true) .addNumberInput_('Buffering Goal', 'streaming.bufferingGoal', - /* canBeDecimal = */ true) + /* canBeDecimal = */ true) .addNumberInput_('Duration Backoff', 'streaming.durationBackoff', - /* canBeDecimal = */ true) + /* canBeDecimal = */ true) .addNumberInput_('Rebuffering Goal', 'streaming.rebufferingGoal', - /* canBeDecimal = */ true) + /* canBeDecimal = */ true) .addNumberInput_('Buffer Behind', 'streaming.bufferBehind', - /* canBeDecimal = */ true) + /* canBeDecimal = */ true) .addNumberInput_('Safe Seek Offset', 'streaming.safeSeekOffset', - /* canBeDecimal = */ true) + /* canBeDecimal = */ true) .addNumberInput_('Stall Threshold', 'streaming.stallThreshold', - /* canBeDecimal = */ true) + /* canBeDecimal = */ true) .addNumberInput_('Safe Skip Distance', 'streaming.stallSkip', - /* canBeDecimal = */ true); + /* canBeDecimal = */ true); if (!shakaDemoMain.getNativeControlsEnabled()) { this.addBoolInput_('Always Stream Text', 'streaming.alwaysStreamText'); @@ -295,9 +295,9 @@ class ShakaDemoConfig { this.addBoolInput_('Jump Large Gaps', 'streaming.jumpLargeGaps') .addBoolInput_('Force Transmux TS', 'streaming.forceTransmuxTS') .addBoolInput_('Start At Segment Boundary', - 'streaming.startAtSegmentBoundary') + 'streaming.startAtSegmentBoundary') .addBoolInput_('Ignore Text Stream Failures', - 'streaming.ignoreTextStreamFailures') + 'streaming.ignoreTextStreamFailures') .addBoolInput_('Stall Detector Enabled', 'streaming.stallEnabled'); this.addRetrySection_('streaming', 'Streaming'); } @@ -314,7 +314,7 @@ class ShakaDemoConfig { this.addCustomTextInput_('Preferred UI Locale', onChange); this.latestInput_.input().value = shakaDemoMain.getUILocale(); this.addNumberInput_('Preferred Audio Channel Count', - 'preferredAudioChannelCount'); + 'preferredAudioChannelCount'); } /** @private */ @@ -354,7 +354,7 @@ class ShakaDemoConfig { const setLevel = shaka['log']['setLevel']; const logLevels = { - 'info': 'Info', 'debug': 'Debug', 'v': 'Verbose', 'vv': 'Very Verbose'}; + 'info': 'Info', 'debug': 'Debug', 'v': 'Verbose', 'vv': 'Very Verbose'}; const onChange = (input) => { switch (input.value) { case 'info': @@ -493,7 +493,7 @@ class ShakaDemoConfig { * @private */ addNumberInput_(name, valueName, canBeDecimal = false, canBeZero = true, - canBeUnset = false, tooltipMessage) { + canBeUnset = false, tooltipMessage) { const onChange = (input) => { shakaDemoMain.resetConfiguration(valueName); shakaDemoMain.remakeHash(); @@ -569,7 +569,7 @@ class ShakaDemoConfig { this.getLatestSection_().addRow(name, tooltipMessage || null); } - /** + /** * Checks for config values that do not have corresponding fields. * @private */ @@ -619,7 +619,7 @@ class ShakaDemoConfig { */ getLatestSection_() { goog.asserts.assert(this.sections_.length > 0, - 'Must have at least one section.'); + 'Must have at least one section.'); return this.sections_[this.sections_.length - 1]; } } diff --git a/demo/custom.js b/demo/custom.js index dd9a9bad7..28b4c3c27 100644 --- a/demo/custom.js +++ b/demo/custom.js @@ -285,8 +285,8 @@ class ShakaDemoCustom { })); buttonsDiv.appendChild(this.makeButton_( 'Cancel', /* isFAB = */ false, () => { - this.dialog_.close(); - })); + this.dialog_.close(); + })); // Update the componentHandler, to account for the new MDL elements. componentHandler.upgradeDom(); @@ -404,11 +404,11 @@ class ShakaDemoCustom { this.savedList_.appendChild(textElement); }; makeMessage('title', - 'Try Shaka Player with your own content!'); + 'Try Shaka Player with your own content!'); makeMessage('body-2', - 'Press the button below to add a custom asset.'); + 'Press the button below to add a custom asset.'); makeMessage('body-1', - 'Custom assets will remain even after reloading the page.'); + 'Custom assets will remain even after reloading the page.'); } else { // Make asset cards for the assets. this.assetCards_ = Array.from(this.assets_).map((asset) => { diff --git a/demo/front.js b/demo/front.js index 543b3ddbf..cc7515394 100644 --- a/demo/front.js +++ b/demo/front.js @@ -80,10 +80,10 @@ class ShakaDemoFront { this.messageDiv_.appendChild(textElement); }; makeMessage('body-2', - 'This is a demo of Google\'s Shaka Player, a JavaScript ' + + 'This is a demo of Google\'s Shaka Player, a JavaScript ' + 'library for adaptive video streaming.'); makeMessage('body-1', - 'Choose a video to playback; more assets are available via ' + + 'Choose a video to playback; more assets are available via ' + 'the search tab.'); const hideButton = document.createElement('button'); diff --git a/demo/input.js b/demo/input.js index fd184132f..39d036e16 100644 --- a/demo/input.js +++ b/demo/input.js @@ -81,16 +81,16 @@ class ShakaDemoInput { return this.extra_; } - /** + /** * @param {string} prefix * @return {string} * @private */ - static generateNewId_(prefix) { - const idNumber = ShakaDemoInput.lastId_; - ShakaDemoInput.lastId_ += 1; - return prefix + '-labeled-' + idNumber; - } + static generateNewId_(prefix) { + const idNumber = ShakaDemoInput.lastId_; + ShakaDemoInput.lastId_ += 1; + return prefix + '-labeled-' + idNumber; + } } diff --git a/demo/main.js b/demo/main.js index c84cb83af..c4ec65d35 100644 --- a/demo/main.js +++ b/demo/main.js @@ -125,7 +125,7 @@ class ShakaDemoMain { this.support_ = await shaka.Player.probeSupport(); this.video_ = - /** @type {!HTMLVideoElement} */(document.getElementById('video')); + /** @type {!HTMLVideoElement} */(document.getElementById('video')); this.video_.poster = ShakaDemoMain.mainPoster_; if (navigator.serviceWorker) { @@ -572,10 +572,10 @@ class ShakaDemoMain { // Construct a new asset. const asset = new ShakaDemoAssetInfo( - /* name= */ 'loaded asset', - /* iconUri= */ '', - /* manifestUri= */ manifest, - /* source= */ shakaAssets.Source.UNKNOWN); + /* name= */ 'loaded asset', + /* iconUri= */ '', + /* manifestUri= */ manifest, + /* source= */ shakaAssets.Source.UNKNOWN); if ('license' in params) { let drmSystems = ShakaDemoMain.commonDrmSystems; if ('drmSystem' in params) { @@ -1108,9 +1108,9 @@ class ShakaDemoMain { dispatchEventWithName_(name) { const event = document.createEvent('CustomEvent'); event.initCustomEvent(name, - /* canBubble = */ false, - /* cancelable = */ false, - /* detail = */ null); + /* canBubble = */ false, + /* cancelable = */ false, + /* detail = */ null); document.dispatchEvent(event); } diff --git a/demo/service_worker.js b/demo/service_worker.js index 41235ea0d..822e85198 100644 --- a/demo/service_worker.js +++ b/demo/service_worker.js @@ -40,7 +40,7 @@ const CACHE_NAME = 'shaka-player-v2.5+'; const CACHE_NAME_PREFIX = 'shaka-player'; console.assert(CACHE_NAME.startsWith(CACHE_NAME_PREFIX), - 'Cache name does not match prefix!'); + 'Cache name does not match prefix!'); /** @@ -171,7 +171,7 @@ function onActivate(event) { // Note that caches are shared across the origin, so only remove // caches we are sure we created. const cleanTheseUp = cacheNames.filter((cacheName) => - cacheName.startsWith(CACHE_NAME_PREFIX) && cacheName != CACHE_NAME); + cacheName.startsWith(CACHE_NAME_PREFIX) && cacheName != CACHE_NAME); const cleanUpPromises = cleanTheseUp.map((cacheName) => caches.delete(cacheName)); diff --git a/lib/abr/ewma_bandwidth_estimator.js b/lib/abr/ewma_bandwidth_estimator.js index b8b691b47..c79bc3daa 100644 --- a/lib/abr/ewma_bandwidth_estimator.js +++ b/lib/abr/ewma_bandwidth_estimator.js @@ -106,14 +106,14 @@ shaka.abr.EwmaBandwidthEstimator.prototype.sample = function( */ shaka.abr.EwmaBandwidthEstimator.prototype.getBandwidthEstimate = function(defaultEstimate) { - if (this.bytesSampled_ < this.minTotalBytes_) { - return defaultEstimate; - } + if (this.bytesSampled_ < this.minTotalBytes_) { + return defaultEstimate; + } - // Take the minimum of these two estimates. This should have the effect of - // adapting down quickly, but up more slowly. - return Math.min(this.fast_.getEstimate(), this.slow_.getEstimate()); -}; + // Take the minimum of these two estimates. This should have the effect of + // adapting down quickly, but up more slowly. + return Math.min(this.fast_.getEstimate(), this.slow_.getEstimate()); + }; /** diff --git a/lib/abr/simple_abr_manager.js b/lib/abr/simple_abr_manager.js index f28e7628d..c69205926 100644 --- a/lib/abr/simple_abr_manager.js +++ b/lib/abr/simple_abr_manager.js @@ -139,9 +139,9 @@ shaka.abr.SimpleAbrManager.prototype.chooseVariant = function() { const maxBandwidth = nextVariant.bandwidth / this.config_.bandwidthUpgradeTarget; shaka.log.v2('Bandwidth ranges:', - (variant.bandwidth / 1e6).toFixed(3), - (minBandwidth / 1e6).toFixed(3), - (maxBandwidth / 1e6).toFixed(3)); + (variant.bandwidth / 1e6).toFixed(3), + (minBandwidth / 1e6).toFixed(3), + (maxBandwidth / 1e6).toFixed(3)); if (currentBandwidth >= minBandwidth && currentBandwidth <= maxBandwidth) { chosen = variant; @@ -178,10 +178,10 @@ shaka.abr.SimpleAbrManager.prototype.disable = function() { shaka.abr.SimpleAbrManager.prototype.segmentDownloaded = function( deltaTimeMs, numBytes) { shaka.log.v2('Segment downloaded:', - 'deltaTimeMs=' + deltaTimeMs, - 'numBytes=' + numBytes, - 'lastTimeChosenMs=' + this.lastTimeChosenMs_, - 'enabled=' + this.enabled_); + 'deltaTimeMs=' + deltaTimeMs, + 'numBytes=' + numBytes, + 'lastTimeChosenMs=' + this.lastTimeChosenMs_, + 'enabled=' + this.enabled_); goog.asserts.assert(deltaTimeMs >= 0, 'expected a non-negative duration'); this.bandwidthEstimator_.sample(deltaTimeMs, numBytes); @@ -227,7 +227,7 @@ shaka.abr.SimpleAbrManager.prototype.configure = function(config) { shaka.abr.SimpleAbrManager.prototype.suggestStreams_ = function() { shaka.log.v2('Suggesting Streams...'); goog.asserts.assert(this.lastTimeChosenMs_ != null, - 'lastTimeChosenMs_ should not be null'); + 'lastTimeChosenMs_ should not be null'); if (!this.startupComplete_) { // Check if we've got enough data yet. diff --git a/lib/cast/cast_proxy.js b/lib/cast/cast_proxy.js index dbe3c6ec5..39d2908a7 100644 --- a/lib/cast/cast_proxy.js +++ b/lib/cast/cast_proxy.js @@ -278,11 +278,11 @@ shaka.cast.CastProxy.prototype.init_ = function() { this.videoEventTarget_ = new shaka.util.FakeEventTarget(); this.videoEventTarget_.dispatchTarget = - /** @type {EventTarget} */(this.videoProxy_); + /** @type {EventTarget} */(this.videoProxy_); this.playerEventTarget_ = new shaka.util.FakeEventTarget(); this.playerEventTarget_.dispatchTarget = - /** @type {EventTarget} */(this.playerProxy_); + /** @type {EventTarget} */(this.playerProxy_); }; @@ -423,7 +423,7 @@ shaka.cast.CastProxy.prototype.onResumeLocal_ = function() { }, (error) => { // Pass any errors through to the app. goog.asserts.assert(error instanceof shaka.util.Error, - 'Wrong error type!'); + 'Wrong error type!'); const event = new shaka.util.FakeEvent('error', {'detail': error}); this.localPlayer_.dispatchEvent(event); }); @@ -604,7 +604,7 @@ shaka.cast.CastProxy.prototype.playerProxyLocalEvent_ = function(event) { */ shaka.cast.CastProxy.prototype.onRemoteEvent_ = function(targetName, event) { goog.asserts.assert(this.sender_.isCasting(), - 'Should only receive remote events while casting'); + 'Should only receive remote events while casting'); if (!this.sender_.isCasting()) { // Ignore any unexpected remote events. return; diff --git a/lib/cast/cast_receiver.js b/lib/cast/cast_receiver.js index 6c5a4ed7a..ba89507bd 100644 --- a/lib/cast/cast_receiver.js +++ b/lib/cast/cast_receiver.js @@ -48,60 +48,60 @@ goog.require('shaka.util.Timer'); */ shaka.cast.CastReceiver = function(video, player, appDataCallback, contentIdCallback) { - shaka.util.FakeEventTarget.call(this); + shaka.util.FakeEventTarget.call(this); - /** @private {HTMLMediaElement} */ - this.video_ = video; + /** @private {HTMLMediaElement} */ + this.video_ = video; - /** @private {shaka.Player} */ - this.player_ = player; + /** @private {shaka.Player} */ + this.player_ = player; - /** @private {shaka.util.EventManager} */ - this.eventManager_ = new shaka.util.EventManager(); + /** @private {shaka.util.EventManager} */ + this.eventManager_ = new shaka.util.EventManager(); - /** @private {Object} */ - this.targets_ = { - 'video': video, - 'player': player, - }; + /** @private {Object} */ + this.targets_ = { + 'video': video, + 'player': player, + }; - /** @private {?function(Object)} */ - this.appDataCallback_ = appDataCallback || function() {}; + /** @private {?function(Object)} */ + this.appDataCallback_ = appDataCallback || function() {}; - /** @private {?function(string):string} */ - this.contentIdCallback_ = contentIdCallback || + /** @private {?function(string):string} */ + this.contentIdCallback_ = contentIdCallback || /** @param {string} contentId @return {string} */ function(contentId) { return contentId; }; - /** @private {boolean} */ - this.isConnected_ = false; + /** @private {boolean} */ + this.isConnected_ = false; - /** @private {boolean} */ - this.isIdle_ = true; + /** @private {boolean} */ + this.isIdle_ = true; - /** @private {number} */ - this.updateNumber_ = 0; + /** @private {number} */ + this.updateNumber_ = 0; - /** @private {boolean} */ - this.startUpdatingUpdateNumber_ = false; + /** @private {boolean} */ + this.startUpdatingUpdateNumber_ = false; - /** @private {boolean} */ - this.initialStatusUpdatePending_ = true; + /** @private {boolean} */ + this.initialStatusUpdatePending_ = true; - /** @private {cast.receiver.CastMessageBus} */ - this.shakaBus_ = null; + /** @private {cast.receiver.CastMessageBus} */ + this.shakaBus_ = null; - /** @private {cast.receiver.CastMessageBus} */ - this.genericBus_ = null; + /** @private {cast.receiver.CastMessageBus} */ + this.genericBus_ = null; - /** @private {shaka.util.Timer} */ - this.pollTimer_ = new shaka.util.Timer(() => { - this.pollAttributes_(); - }); + /** @private {shaka.util.Timer} */ + this.pollTimer_ = new shaka.util.Timer(() => { + this.pollAttributes_(); + }); - this.init_(); -}; + this.init_(); + }; goog.inherits(shaka.cast.CastReceiver, shaka.util.FakeEventTarget); @@ -354,7 +354,7 @@ shaka.cast.CastReceiver.prototype.initState_ = function(initState, appData) { }, (error) => { // Pass any errors through to the app. goog.asserts.assert(error instanceof shaka.util.Error, - 'Wrong error type!'); + 'Wrong error type!'); const event = new shaka.util.FakeEvent('error', {'detail': error}); this.player_.dispatchEvent(event); }); @@ -407,7 +407,7 @@ shaka.cast.CastReceiver.prototype.pollAttributes_ = function() { if (this.player_.isLive()) { for (const name in - shaka.cast.CastUtils.PlayerGetterMethodsThatRequireLive) { + shaka.cast.CastUtils.PlayerGetterMethodsThatRequireLive) { const frequency = shaka.cast.CastUtils.PlayerGetterMethodsThatRequireLive[name]; if (this.updateNumber_ % frequency == 0) { @@ -596,7 +596,7 @@ shaka.cast.CastReceiver.prototype.onShakaMessage_ = function(event) { // Replies must go back to the specific sender who initiated, so that we // don't have to deal with conflicting IDs between senders. p.then(this.sendAsyncComplete_.bind(this, senderId, id, /* error */ null), - this.sendAsyncComplete_.bind(this, senderId, id)); + this.sendAsyncComplete_.bind(this, senderId, id)); break; } } @@ -736,17 +736,17 @@ shaka.cast.CastReceiver.prototype.onGenericMessage_ = function(event) { */ shaka.cast.CastReceiver.prototype.sendAsyncComplete_ = function(senderId, id, error) { - if (!this.player_) { - // We've already been destroyed. - return; - } + if (!this.player_) { + // We've already been destroyed. + return; + } - this.sendMessage_({ - 'type': 'asyncComplete', - 'id': id, - 'error': error, - }, this.shakaBus_, senderId); -}; + this.sendMessage_({ + 'type': 'asyncComplete', + 'id': id, + 'error': error, + }, this.shakaBus_, senderId); + }; /** @@ -759,18 +759,18 @@ shaka.cast.CastReceiver.prototype.sendAsyncComplete_ = */ shaka.cast.CastReceiver.prototype.sendMessage_ = function(message, bus, senderId) { - // Cuts log spam when debugging the receiver UI in Chrome. - if (!this.isConnected_) { - return; - } + // Cuts log spam when debugging the receiver UI in Chrome. + if (!this.isConnected_) { + return; + } - const serialized = shaka.cast.CastUtils.serialize(message); - if (senderId) { - bus.getCastChannel(senderId).send(serialized); - } else { - bus.broadcast(serialized); - } -}; + const serialized = shaka.cast.CastUtils.serialize(message); + if (senderId) { + bus.getCastChannel(senderId).send(serialized); + } else { + bus.broadcast(serialized); + } + }; /** @@ -798,44 +798,44 @@ shaka.cast.CastReceiver.prototype.getPlayState_ = function() { */ shaka.cast.CastReceiver.prototype.sendMediaStatus_ = function(requestId, media) { - const mediaStatus = { - // mediaSessionId is a unique ID for the playback of this specific session. - // It's used to identify a specific instance of a playback. - // We don't support multiple playbacks, so just return 0. - 'mediaSessionId': 0, - 'playbackRate': this.video_.playbackRate, - 'playerState': this.getPlayState_(), - 'currentTime': this.video_.currentTime, - // supportedMediaCommands is a sum of all the flags of commands that the - // player supports. - // The list of comands with respective flags is: - // 1 - Pause - // 2 - Seek - // 4 - Stream volume - // 8 - Stream mute - // 16 - Skip forward - // 32 - Skip backward - // We support pause, seek, volume and mute which gives a value of - // 1+2+4+8=15 - 'supportedMediaCommands': 15, - 'volume': { - 'level': this.video_.volume, - 'muted': this.video_.muted, - }, - }; + const mediaStatus = { + // mediaSessionId is a unique ID for the playback of this specific session. + // It's used to identify a specific instance of a playback. + // We don't support multiple playbacks, so just return 0. + 'mediaSessionId': 0, + 'playbackRate': this.video_.playbackRate, + 'playerState': this.getPlayState_(), + 'currentTime': this.video_.currentTime, + // supportedMediaCommands is a sum of all the flags of commands that the + // player supports. + // The list of comands with respective flags is: + // 1 - Pause + // 2 - Seek + // 4 - Stream volume + // 8 - Stream mute + // 16 - Skip forward + // 32 - Skip backward + // We support pause, seek, volume and mute which gives a value of + // 1+2+4+8=15 + 'supportedMediaCommands': 15, + 'volume': { + 'level': this.video_.volume, + 'muted': this.video_.muted, + }, + }; - if (media) { - mediaStatus['media'] = media; - } + if (media) { + mediaStatus['media'] = media; + } - const ret = { - 'requestId': requestId, - 'type': 'MEDIA_STATUS', - 'status': [mediaStatus], - }; + const ret = { + 'requestId': requestId, + 'type': 'MEDIA_STATUS', + 'status': [mediaStatus], + }; - this.sendMessage_(ret, this.genericBus_); -}; + this.sendMessage_(ret, this.genericBus_); + }; /** diff --git a/lib/cast/cast_sender.js b/lib/cast/cast_sender.js index 1629d6ad8..c14dca17e 100644 --- a/lib/cast/cast_sender.js +++ b/lib/cast/cast_sender.js @@ -44,62 +44,62 @@ goog.require('shaka.util.PublicPromise'); */ shaka.cast.CastSender = function(receiverAppId, onStatusChanged, onFirstCastStateUpdate, - onRemoteEvent, onResumeLocal, onInitStateRequired) { - /** @private {string} */ - this.receiverAppId_ = receiverAppId; + onRemoteEvent, onResumeLocal, onInitStateRequired) { + /** @private {string} */ + this.receiverAppId_ = receiverAppId; - /** @private {shaka.util.Timer} */ - this.statusChangeTimer_ = new shaka.util.Timer(onStatusChanged); + /** @private {shaka.util.Timer} */ + this.statusChangeTimer_ = new shaka.util.Timer(onStatusChanged); - /** @private {?function()} */ - this.onFirstCastStateUpdate_ = onFirstCastStateUpdate; + /** @private {?function()} */ + this.onFirstCastStateUpdate_ = onFirstCastStateUpdate; - /** @private {boolean} */ - this.hasJoinedExistingSession_ = false; + /** @private {boolean} */ + this.hasJoinedExistingSession_ = false; - /** @private {?function(string, !shaka.util.FakeEvent)} */ - this.onRemoteEvent_ = onRemoteEvent; + /** @private {?function(string, !shaka.util.FakeEvent)} */ + this.onRemoteEvent_ = onRemoteEvent; - /** @private {?function()} */ - this.onResumeLocal_ = onResumeLocal; + /** @private {?function()} */ + this.onResumeLocal_ = onResumeLocal; - /** @private {?function()} */ - this.onInitStateRequired_ = onInitStateRequired; + /** @private {?function()} */ + this.onInitStateRequired_ = onInitStateRequired; - /** @private {boolean} */ - this.apiReady_ = false; + /** @private {boolean} */ + this.apiReady_ = false; - /** @private {boolean} */ - this.isCasting_ = false; + /** @private {boolean} */ + this.isCasting_ = false; - /** @private {string} */ - this.receiverName_ = ''; + /** @private {string} */ + this.receiverName_ = ''; - /** @private {Object} */ - this.appData_ = null; + /** @private {Object} */ + this.appData_ = null; - /** @private {?function()} */ - this.onConnectionStatusChangedBound_ = + /** @private {?function()} */ + this.onConnectionStatusChangedBound_ = this.onConnectionStatusChanged_.bind(this); - /** @private {?function(string, string)} */ - this.onMessageReceivedBound_ = this.onMessageReceived_.bind(this); + /** @private {?function(string, string)} */ + this.onMessageReceivedBound_ = this.onMessageReceived_.bind(this); - /** @private {Object} */ - this.cachedProperties_ = { - 'video': {}, - 'player': {}, - }; + /** @private {Object} */ + this.cachedProperties_ = { + 'video': {}, + 'player': {}, + }; - /** @private {number} */ - this.nextAsyncCallId_ = 0; + /** @private {number} */ + this.nextAsyncCallId_ = 0; - /** @private {Object.} */ - this.asyncCallPromises_ = {}; + /** @private {Object.} */ + this.asyncCallPromises_ = {}; - /** @private {shaka.util.PublicPromise} */ - this.castPromise_ = null; -}; + /** @private {shaka.util.PublicPromise} */ + this.castPromise_ = null; + }; /** @private {boolean} */ @@ -321,7 +321,7 @@ shaka.cast.CastSender.prototype.forceDisconnect = function() { */ shaka.cast.CastSender.prototype.get = function(targetName, property) { goog.asserts.assert(targetName == 'video' || targetName == 'player', - 'Unexpected target name'); + 'Unexpected target name'); const CastUtils = shaka.cast.CastUtils; if (targetName == 'video') { if (CastUtils.VideoVoidMethods.includes(property)) { @@ -361,7 +361,7 @@ shaka.cast.CastSender.prototype.get = function(targetName, property) { */ shaka.cast.CastSender.prototype.set = function(targetName, property, value) { goog.asserts.assert(targetName == 'video' || targetName == 'player', - 'Unexpected target name'); + 'Unexpected target name'); this.cachedProperties_[targetName][property] = value; this.sendMessage_({ @@ -380,17 +380,17 @@ shaka.cast.CastSender.prototype.set = function(targetName, property, value) { */ shaka.cast.CastSender.prototype.onSessionInitiated_ = function(initState, session) { - shaka.log.debug('CastSender: onSessionInitiated'); - this.onSessionCreated_(session); + shaka.log.debug('CastSender: onSessionInitiated'); + this.onSessionCreated_(session); - this.sendMessage_({ - 'type': 'init', - 'initState': initState, - 'appData': this.appData_, - }); + this.sendMessage_({ + 'type': 'init', + 'initState': initState, + 'appData': this.appData_, + }); - this.castPromise_.resolve(); -}; + this.castPromise_.resolve(); + }; /** @@ -429,10 +429,10 @@ shaka.cast.CastSender.prototype.onConnectionError_ = function(error) { */ shaka.cast.CastSender.prototype.propertyGetter_ = function(targetName, property) { - goog.asserts.assert(targetName == 'video' || targetName == 'player', - 'Unexpected target name'); - return this.cachedProperties_[targetName][property]; -}; + goog.asserts.assert(targetName == 'video' || targetName == 'player', + 'Unexpected target name'); + return this.cachedProperties_[targetName][property]; + }; /** @@ -443,15 +443,15 @@ shaka.cast.CastSender.prototype.propertyGetter_ = */ shaka.cast.CastSender.prototype.remoteCall_ = function(targetName, methodName, ...varArgs) { - goog.asserts.assert(targetName == 'video' || targetName == 'player', - 'Unexpected target name'); - this.sendMessage_({ - 'type': 'call', - 'targetName': targetName, - 'methodName': methodName, - 'args': varArgs, - }); -}; + goog.asserts.assert(targetName == 'video' || targetName == 'player', + 'Unexpected target name'); + this.sendMessage_({ + 'type': 'call', + 'targetName': targetName, + 'methodName': methodName, + 'args': varArgs, + }); + }; /** @@ -463,23 +463,23 @@ shaka.cast.CastSender.prototype.remoteCall_ = */ shaka.cast.CastSender.prototype.remoteAsyncCall_ = function(targetName, methodName, ...varArgs) { - goog.asserts.assert(targetName == 'video' || targetName == 'player', - 'Unexpected target name'); + goog.asserts.assert(targetName == 'video' || targetName == 'player', + 'Unexpected target name'); - const p = new shaka.util.PublicPromise(); - const id = this.nextAsyncCallId_.toString(); - this.nextAsyncCallId_++; - this.asyncCallPromises_[id] = p; + const p = new shaka.util.PublicPromise(); + const id = this.nextAsyncCallId_.toString(); + this.nextAsyncCallId_++; + this.asyncCallPromises_[id] = p; - this.sendMessage_({ - 'type': 'asyncCall', - 'targetName': targetName, - 'methodName': methodName, - 'args': varArgs, - 'id': id, - }); - return p; -}; + this.sendMessage_({ + 'type': 'asyncCall', + 'targetName': targetName, + 'methodName': methodName, + 'args': varArgs, + 'id': id, + }); + return p; + }; /** @@ -504,12 +504,12 @@ shaka.cast.CastSender.prototype.onExistingSessionJoined_ = function(session) { */ shaka.cast.CastSender.prototype.onReceiverStatusChanged_ = function(availability) { - // The cast extension is telling us whether there are any cast receiver - // devices available. - shaka.log.debug('CastSender: receiver status', availability); - shaka.cast.CastSender.hasReceivers_ = availability == 'available'; - this.statusChangeTimer_.tickNow(); -}; + // The cast extension is telling us whether there are any cast receiver + // devices available. + shaka.log.debug('CastSender: receiver status', availability); + shaka.cast.CastSender.hasReceivers_ = availability == 'available'; + this.statusChangeTimer_.tickNow(); + }; /** @@ -590,60 +590,60 @@ shaka.cast.CastSender.prototype.rejectAllPromises_ = function() { */ shaka.cast.CastSender.prototype.onMessageReceived_ = function(namespace, serialized) { - // Since this method is in the compiled library, make sure all messages passed - // in here were created with quoted property names. + // Since this method is in the compiled library, make sure all messages passed + // in here were created with quoted property names. - const message = shaka.cast.CastUtils.deserialize(serialized); - shaka.log.v2('CastSender: message', message); + const message = shaka.cast.CastUtils.deserialize(serialized); + shaka.log.v2('CastSender: message', message); - switch (message['type']) { - case 'event': { - const targetName = message['targetName']; - const event = message['event']; - const fakeEvent = new shaka.util.FakeEvent(event['type'], event); - this.onRemoteEvent_(targetName, fakeEvent); - break; - } - case 'update': { - const update = message['update']; - for (const targetName in update) { - const target = this.cachedProperties_[targetName] || {}; - for (const property in update[targetName]) { - target[property] = update[targetName][property]; + switch (message['type']) { + case 'event': { + const targetName = message['targetName']; + const event = message['event']; + const fakeEvent = new shaka.util.FakeEvent(event['type'], event); + this.onRemoteEvent_(targetName, fakeEvent); + break; + } + case 'update': { + const update = message['update']; + for (const targetName in update) { + const target = this.cachedProperties_[targetName] || {}; + for (const property in update[targetName]) { + target[property] = update[targetName][property]; + } + } + if (this.hasJoinedExistingSession_) { + this.onFirstCastStateUpdate_(); + this.hasJoinedExistingSession_ = false; + } + break; + } + case 'asyncComplete': { + const id = message['id']; + const error = message['error']; + const p = this.asyncCallPromises_[id]; + delete this.asyncCallPromises_[id]; + + goog.asserts.assert(p, 'Unexpected async id'); + if (!p) { + break; + } + + if (error) { + // This is a hacky way to reconstruct the serialized error. + const reconstructedError = new shaka.util.Error( + error.severity, error.category, error.code); + for (const k in error) { + (/** @type {Object} */(reconstructedError))[k] = error[k]; + } + p.reject(reconstructedError); + } else { + p.resolve(); + } + break; } } - if (this.hasJoinedExistingSession_) { - this.onFirstCastStateUpdate_(); - this.hasJoinedExistingSession_ = false; - } - break; - } - case 'asyncComplete': { - const id = message['id']; - const error = message['error']; - const p = this.asyncCallPromises_[id]; - delete this.asyncCallPromises_[id]; - - goog.asserts.assert(p, 'Unexpected async id'); - if (!p) { - break; - } - - if (error) { - // This is a hacky way to reconstruct the serialized error. - const reconstructedError = new shaka.util.Error( - error.severity, error.category, error.code); - for (const k in error) { - (/** @type {Object} */(reconstructedError))[k] = error[k]; - } - p.reject(reconstructedError); - } else { - p.resolve(); - } - break; - } - } -}; + }; /** @@ -658,7 +658,7 @@ shaka.cast.CastSender.prototype.sendMessage_ = function(message) { // TODO: have never seen this fail. When would it and how should we react? const session = shaka.cast.CastSender.session_; session.sendMessage(shaka.cast.CastUtils.SHAKA_MESSAGE_NAMESPACE, - serialized, - () => {}, // success callback - shaka.log.error); // error callback + serialized, + () => {}, // success callback + shaka.log.error); // error callback }; diff --git a/lib/dash/content_protection.js b/lib/dash/content_protection.js index 4d345d374..5da3e22fb 100644 --- a/lib/dash/content_protection.js +++ b/lib/dash/content_protection.js @@ -93,13 +93,13 @@ shaka.dash.ContentProtection.Element; */ shaka.dash.ContentProtection.defaultKeySystems_ = new Map() .set('urn:uuid:1077efec-c0b2-4d02-ace3-3c1e52e2fb4b', - 'org.w3.clearkey') + 'org.w3.clearkey') .set('urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed', - 'com.widevine.alpha') + 'com.widevine.alpha') .set('urn:uuid:9a04f079-9840-4286-ab92-e65be0885f95', - 'com.microsoft.playready') + 'com.microsoft.playready') .set('urn:uuid:f239e769-efa3-4850-9c16-a903c6932efb', - 'com.adobe.primetime'); + 'com.adobe.primetime'); /** @@ -154,7 +154,7 @@ shaka.dash.ContentProtection.parseFromAdaptationSet = function( parsedNonCenc = parsed.filter((elem) => { if (elem.schemeUri == ContentProtection.MP4Protection_) { goog.asserts.assert(!elem.init || elem.init.length, - 'Init data must be null or non-empty.'); + 'Init data must be null or non-empty.'); defaultInit = elem.init || defaultInit; return false; } else { @@ -271,7 +271,7 @@ shaka.dash.ContentProtection.parseFromRepresentation = function( */ shaka.dash.ContentProtection.getWidevineLicenseUrl = function(element) { const mslaurlNode = shaka.util.XmlUtils.findChildNS( - element.node, 'urn:microsoft', 'laurl'); + element.node, 'urn:microsoft', 'laurl'); if (mslaurlNode) { return mslaurlNode.getAttribute('licenseUrl') || ''; } @@ -318,7 +318,7 @@ shaka.dash.ContentProtection.PLAYREADY_RECORD_TYPES = { * @private */ shaka.dash.ContentProtection.parseMsProRecords_ = function( - recordData, byteOffset) { + recordData, byteOffset) { const records = []; const view = new DataView(recordData); @@ -330,8 +330,8 @@ shaka.dash.ContentProtection.parseMsProRecords_ = function( byteOffset += 2; goog.asserts.assert( - (byteLength & 1) === 0, - 'expected byteLength to be an even number'); + (byteLength & 1) === 0, + 'expected byteLength to be an even number'); const recordValue = new Uint8Array(recordData, byteOffset, byteLength); @@ -413,7 +413,7 @@ shaka.dash.ContentProtection.getLaurl_ = function(xml) { */ shaka.dash.ContentProtection.getPlayReadyLicenseUrl = function(element) { const proNode = shaka.util.XmlUtils.findChildNS( - element.node, 'urn:microsoft:playready', 'pro'); + element.node, 'urn:microsoft:playready', 'pro'); if (!proNode) { return ''; @@ -452,7 +452,7 @@ shaka.dash.ContentProtection.getPlayReadyLicenseUrl = function(element) { * @private */ shaka.dash.ContentProtection.convertElements_ = function( - defaultInit, callback, elements) { + defaultInit, callback, elements) { const ContentProtection = shaka.dash.ContentProtection; const ManifestParserUtils = shaka.util.ManifestParserUtils; const defaultKeySystems = ContentProtection.defaultKeySystems_; @@ -497,9 +497,9 @@ shaka.dash.ContentProtection.convertElements_ = function( */ shaka.dash.ContentProtection.licenseUrlParsers_ = new Map() .set('com.widevine.alpha', - shaka.dash.ContentProtection.getWidevineLicenseUrl) + shaka.dash.ContentProtection.getWidevineLicenseUrl) .set('com.microsoft.playready', - shaka.dash.ContentProtection.getPlayReadyLicenseUrl); + shaka.dash.ContentProtection.getPlayReadyLicenseUrl); /** @@ -541,11 +541,11 @@ shaka.dash.ContentProtection.parseElement_ = function(elem) { let keyId = shaka.util.XmlUtils.getAttributeNS(elem, NS, 'default_KID'); /** @type {!Array.} */ const psshs = shaka.util.XmlUtils.findChildrenNS(elem, NS, 'pssh') - .map(shaka.util.XmlUtils.getContents); + .map(shaka.util.XmlUtils.getContents); if (!schemeUri) { shaka.log.error('Missing required schemeIdUri attribute on', - 'ContentProtection element', elem); + 'ContentProtection element', elem); return null; } diff --git a/lib/dash/dash_parser.js b/lib/dash/dash_parser.js index 6cd7533ef..d73c6c18b 100644 --- a/lib/dash/dash_parser.js +++ b/lib/dash/dash_parser.js @@ -319,7 +319,7 @@ shaka.dash.DashParser.StreamInfo; */ shaka.dash.DashParser.prototype.configure = function(config) { goog.asserts.assert(config.dash != null, - 'DashManifestConfiguration should not be null!'); + 'DashManifestConfiguration should not be null!'); this.config_ = config; }; @@ -454,25 +454,25 @@ shaka.dash.DashParser.prototype.requestManifest_ = async function() { */ shaka.dash.DashParser.prototype.parseManifest_ = async function(data, finalManifestUri) { - const Error = shaka.util.Error; - const MpdUtils = shaka.dash.MpdUtils; + const Error = shaka.util.Error; + const MpdUtils = shaka.dash.MpdUtils; - const mpd = shaka.util.XmlUtils.parseXml(data, 'MPD'); - if (!mpd) { - throw new Error( - Error.Severity.CRITICAL, Error.Category.MANIFEST, - Error.Code.DASH_INVALID_XML, finalManifestUri); - } + const mpd = shaka.util.XmlUtils.parseXml(data, 'MPD'); + if (!mpd) { + throw new Error( + Error.Severity.CRITICAL, Error.Category.MANIFEST, + Error.Code.DASH_INVALID_XML, finalManifestUri); + } - // Process the mpd to account for xlink connections. - const failGracefully = this.config_.dash.xlinkFailGracefully; - const xlinkOperation = MpdUtils.processXlinks( - mpd, this.config_.retryParameters, failGracefully, finalManifestUri, - this.playerInterface_.networkingEngine); - this.operationManager_.manage(xlinkOperation); - const finalMpd = await xlinkOperation.promise; - return this.processManifest_(finalMpd, finalManifestUri); -}; + // Process the mpd to account for xlink connections. + const failGracefully = this.config_.dash.xlinkFailGracefully; + const xlinkOperation = MpdUtils.processXlinks( + mpd, this.config_.retryParameters, failGracefully, finalManifestUri, + this.playerInterface_.networkingEngine); + this.operationManager_.manage(xlinkOperation); + const finalMpd = await xlinkOperation.promise; + return this.processManifest_(finalMpd, finalManifestUri); + }; /** @@ -487,140 +487,140 @@ shaka.dash.DashParser.prototype.parseManifest_ = */ shaka.dash.DashParser.prototype.processManifest_ = async function(mpd, finalManifestUri) { - const Functional = shaka.util.Functional; - const XmlUtils = shaka.util.XmlUtils; + const Functional = shaka.util.Functional; + const XmlUtils = shaka.util.XmlUtils; - // Get any Location elements. This will update the manifest location and - // the base URI. - /** @type {!Array.} */ - let manifestBaseUris = [finalManifestUri]; - /** @type {!Array.} */ - const locations = XmlUtils.findChildren(mpd, 'Location') - .map(XmlUtils.getContents) - .filter(Functional.isNotNull); - if (locations.length > 0) { - const absoluteLocations = shaka.util.ManifestParserUtils.resolveUris( - manifestBaseUris, locations); - this.manifestUris_ = absoluteLocations; - manifestBaseUris = absoluteLocations; - } - - const uris = XmlUtils.findChildren(mpd, 'BaseURL').map(XmlUtils.getContents); - const baseUris = shaka.util.ManifestParserUtils.resolveUris( - manifestBaseUris, uris); - - const ignoreMinBufferTime = this.config_.dash.ignoreMinBufferTime; - let minBufferTime; - if (!ignoreMinBufferTime) { - minBufferTime = - XmlUtils.parseAttr(mpd, 'minBufferTime', XmlUtils.parseDuration); - } - - this.updatePeriod_ = /** @type {number} */ (XmlUtils.parseAttr( - mpd, 'minimumUpdatePeriod', XmlUtils.parseDuration, -1)); - - const presentationStartTime = XmlUtils.parseAttr( - mpd, 'availabilityStartTime', XmlUtils.parseDate); - let segmentAvailabilityDuration = XmlUtils.parseAttr( - mpd, 'timeShiftBufferDepth', XmlUtils.parseDuration); - const suggestedPresentationDelay = XmlUtils.parseAttr( - mpd, 'suggestedPresentationDelay', XmlUtils.parseDuration); - const maxSegmentDuration = XmlUtils.parseAttr( - mpd, 'maxSegmentDuration', XmlUtils.parseDuration); - const mpdType = mpd.getAttribute('type') || 'static'; - - /** @type {!shaka.media.PresentationTimeline} */ - let presentationTimeline; - if (this.manifest_) { - presentationTimeline = this.manifest_.presentationTimeline; - } else { - // DASH IOP v3.0 suggests using a default delay between minBufferTime and - // timeShiftBufferDepth. This is literally the range of all feasible - // choices for the value. Nothing older than timeShiftBufferDepth is still - // available, and anything less than minBufferTime will cause buffering - // issues. - // - // We have decided that our default will be 1.5 * minBufferTime, - // or 10s (configurable) whichever is larger. This is fairly conservative. - // Content providers should provide a suggestedPresentationDelay - // whenever possible to optimize the live streaming experience. - const defaultPresentationDelay = Math.max( - this.config_.dash.defaultPresentationDelay, - minBufferTime * 1.5); - const presentationDelay = suggestedPresentationDelay != null ? - suggestedPresentationDelay : defaultPresentationDelay; - presentationTimeline = new shaka.media.PresentationTimeline( - presentationStartTime, presentationDelay, - this.config_.dash.autoCorrectDrift); - } - - /** @type {shaka.dash.DashParser.Context} */ - const context = { - // Don't base on updatePeriod_ since emsg boxes can cause manifest updates. - dynamic: mpdType != 'static', - presentationTimeline: presentationTimeline, - period: null, - periodInfo: null, - adaptationSet: null, - representation: null, - bandwidth: 0, - indexRangeWarningGiven: false, - }; - - const periodsAndDuration = this.parsePeriods_(context, baseUris, mpd); - const duration = periodsAndDuration.duration; - const periods = periodsAndDuration.periods; - - presentationTimeline.setStatic(mpdType == 'static'); - if (mpdType == 'static' || !periodsAndDuration.durationDerivedFromPeriods) { - // Ignore duration calculated from Period lengths if this is dynamic. - presentationTimeline.setDuration(duration || Infinity); - } - - const isLive = presentationTimeline.isLive(); - - // If it's live, we check for an override. - if (isLive && !isNaN(this.config_.availabilityWindowOverride)) { - segmentAvailabilityDuration = this.config_.availabilityWindowOverride; - } - - // If it's null, that means segments are always available. This is always the - // case for VOD, and sometimes the case for live. - if (segmentAvailabilityDuration == null) { - segmentAvailabilityDuration = Infinity; - } - - presentationTimeline.setSegmentAvailabilityDuration( - segmentAvailabilityDuration); - - // Use @maxSegmentDuration to override smaller, derived values. - presentationTimeline.notifyMaxSegmentDuration(maxSegmentDuration || 1); - if (goog.DEBUG) { - presentationTimeline.assertIsValid(); - } - - // These steps are not done on manifest update. - if (!this.manifest_) { - this.manifest_ = { - presentationTimeline: presentationTimeline, - periods: periods, - offlineSessionIds: [], - minBufferTime: minBufferTime || 0, - }; - - // We only need to do clock sync when we're using presentation start time. - // This condition also excludes VOD streams. - if (presentationTimeline.usingPresentationStartTime()) { - const timingElements = XmlUtils.findChildren(mpd, 'UTCTiming'); - const offset = await this.parseUtcTiming_(baseUris, timingElements); - // Detect calls to stop(). - if (!this.playerInterface_) { - return; + // Get any Location elements. This will update the manifest location and + // the base URI. + /** @type {!Array.} */ + let manifestBaseUris = [finalManifestUri]; + /** @type {!Array.} */ + const locations = XmlUtils.findChildren(mpd, 'Location') + .map(XmlUtils.getContents) + .filter(Functional.isNotNull); + if (locations.length > 0) { + const absoluteLocations = shaka.util.ManifestParserUtils.resolveUris( + manifestBaseUris, locations); + this.manifestUris_ = absoluteLocations; + manifestBaseUris = absoluteLocations; } - presentationTimeline.setClockOffset(offset); - } - } -}; + + const uris = XmlUtils.findChildren(mpd, 'BaseURL').map(XmlUtils.getContents); + const baseUris = shaka.util.ManifestParserUtils.resolveUris( + manifestBaseUris, uris); + + const ignoreMinBufferTime = this.config_.dash.ignoreMinBufferTime; + let minBufferTime; + if (!ignoreMinBufferTime) { + minBufferTime = + XmlUtils.parseAttr(mpd, 'minBufferTime', XmlUtils.parseDuration); + } + + this.updatePeriod_ = /** @type {number} */ (XmlUtils.parseAttr( + mpd, 'minimumUpdatePeriod', XmlUtils.parseDuration, -1)); + + const presentationStartTime = XmlUtils.parseAttr( + mpd, 'availabilityStartTime', XmlUtils.parseDate); + let segmentAvailabilityDuration = XmlUtils.parseAttr( + mpd, 'timeShiftBufferDepth', XmlUtils.parseDuration); + const suggestedPresentationDelay = XmlUtils.parseAttr( + mpd, 'suggestedPresentationDelay', XmlUtils.parseDuration); + const maxSegmentDuration = XmlUtils.parseAttr( + mpd, 'maxSegmentDuration', XmlUtils.parseDuration); + const mpdType = mpd.getAttribute('type') || 'static'; + + /** @type {!shaka.media.PresentationTimeline} */ + let presentationTimeline; + if (this.manifest_) { + presentationTimeline = this.manifest_.presentationTimeline; + } else { + // DASH IOP v3.0 suggests using a default delay between minBufferTime and + // timeShiftBufferDepth. This is literally the range of all feasible + // choices for the value. Nothing older than timeShiftBufferDepth is still + // available, and anything less than minBufferTime will cause buffering + // issues. + // + // We have decided that our default will be 1.5 * minBufferTime, + // or 10s (configurable) whichever is larger. This is fairly conservative. + // Content providers should provide a suggestedPresentationDelay + // whenever possible to optimize the live streaming experience. + const defaultPresentationDelay = Math.max( + this.config_.dash.defaultPresentationDelay, + minBufferTime * 1.5); + const presentationDelay = suggestedPresentationDelay != null ? + suggestedPresentationDelay : defaultPresentationDelay; + presentationTimeline = new shaka.media.PresentationTimeline( + presentationStartTime, presentationDelay, + this.config_.dash.autoCorrectDrift); + } + + /** @type {shaka.dash.DashParser.Context} */ + const context = { + // Don't base on updatePeriod_ since emsg boxes can cause manifest updates. + dynamic: mpdType != 'static', + presentationTimeline: presentationTimeline, + period: null, + periodInfo: null, + adaptationSet: null, + representation: null, + bandwidth: 0, + indexRangeWarningGiven: false, + }; + + const periodsAndDuration = this.parsePeriods_(context, baseUris, mpd); + const duration = periodsAndDuration.duration; + const periods = periodsAndDuration.periods; + + presentationTimeline.setStatic(mpdType == 'static'); + if (mpdType == 'static' || !periodsAndDuration.durationDerivedFromPeriods) { + // Ignore duration calculated from Period lengths if this is dynamic. + presentationTimeline.setDuration(duration || Infinity); + } + + const isLive = presentationTimeline.isLive(); + + // If it's live, we check for an override. + if (isLive && !isNaN(this.config_.availabilityWindowOverride)) { + segmentAvailabilityDuration = this.config_.availabilityWindowOverride; + } + + // If it's null, that means segments are always available. This is always the + // case for VOD, and sometimes the case for live. + if (segmentAvailabilityDuration == null) { + segmentAvailabilityDuration = Infinity; + } + + presentationTimeline.setSegmentAvailabilityDuration( + segmentAvailabilityDuration); + + // Use @maxSegmentDuration to override smaller, derived values. + presentationTimeline.notifyMaxSegmentDuration(maxSegmentDuration || 1); + if (goog.DEBUG) { + presentationTimeline.assertIsValid(); + } + + // These steps are not done on manifest update. + if (!this.manifest_) { + this.manifest_ = { + presentationTimeline: presentationTimeline, + periods: periods, + offlineSessionIds: [], + minBufferTime: minBufferTime || 0, + }; + + // We only need to do clock sync when we're using presentation start time. + // This condition also excludes VOD streams. + if (presentationTimeline.usingPresentationStartTime()) { + const timingElements = XmlUtils.findChildren(mpd, 'UTCTiming'); + const offset = await this.parseUtcTiming_(baseUris, timingElements); + // Detect calls to stop(). + if (!this.playerInterface_) { + return; + } + presentationTimeline.setClockOffset(offset); + } + } + }; /** @@ -649,7 +649,7 @@ shaka.dash.DashParser.prototype.parsePeriods_ = function( for (let i = 0; i < periodNodes.length; i++) { const elem = periodNodes[i]; const start = /** @type {number} */ ( - XmlUtils.parseAttr(elem, 'start', XmlUtils.parseDuration, prevEnd)); + XmlUtils.parseAttr(elem, 'start', XmlUtils.parseDuration, prevEnd)); const givenDuration = XmlUtils.parseAttr(elem, 'duration', XmlUtils.parseDuration); @@ -905,44 +905,65 @@ shaka.dash.DashParser.prototype.getSetsOfType_ = function( */ shaka.dash.DashParser.prototype.createVariants_ = function(audio, video, variants) { - const ContentType = shaka.util.ManifestParserUtils.ContentType; + const ContentType = shaka.util.ManifestParserUtils.ContentType; - // Since both audio and video are of the same type, this assertion will catch - // certain mistakes at runtime that the compiler would miss. - goog.asserts.assert(!audio || audio.contentType == ContentType.AUDIO, - 'Audio parameter mismatch!'); - goog.asserts.assert(!video || video.contentType == ContentType.VIDEO, - 'Video parameter mismatch!'); + // Since both audio and video are of the same type, this assertion will catch + // certain mistakes at runtime that the compiler would miss. + goog.asserts.assert(!audio || audio.contentType == ContentType.AUDIO, + 'Audio parameter mismatch!'); + goog.asserts.assert(!video || video.contentType == ContentType.VIDEO, + 'Video parameter mismatch!'); - /** @type {number} */ - let bandwidth; - /** @type {shaka.extern.Variant} */ - let variant; + /** @type {number} */ + let bandwidth; + /** @type {shaka.extern.Variant} */ + let variant; - if (!audio && !video) { - return; - } + if (!audio && !video) { + return; + } - if (audio && video) { - // Audio+video variants - const DrmEngine = shaka.media.DrmEngine; - if (DrmEngine.areDrmCompatible(audio.drmInfos, video.drmInfos)) { - const drmInfos = DrmEngine.getCommonDrmInfos(audio.drmInfos, - video.drmInfos); + if (audio && video) { + // Audio+video variants + const DrmEngine = shaka.media.DrmEngine; + if (DrmEngine.areDrmCompatible(audio.drmInfos, video.drmInfos)) { + const drmInfos = DrmEngine.getCommonDrmInfos(audio.drmInfos, + video.drmInfos); - for (let i = 0; i < audio.streams.length; i++) { - for (let j = 0; j < video.streams.length; j++) { - bandwidth = + for (let i = 0; i < audio.streams.length; i++) { + for (let j = 0; j < video.streams.length; j++) { + bandwidth = (video.streams[j].bandwidth || 0) + (audio.streams[i].bandwidth || 0); + variant = { + id: this.globalId_++, + language: audio.language, + primary: audio.main || video.main, + audio: audio.streams[i], + video: video.streams[j], + bandwidth: bandwidth, + drmInfos: drmInfos, + allowedByApplication: true, + allowedByKeySystem: true, + }; + + variants.push(variant); + } + } + } + } else { + // Audio or video only variants + const set = audio || video; + for (let i = 0; i < set.streams.length; i++) { + bandwidth = set.streams[i].bandwidth || 0; variant = { id: this.globalId_++, - language: audio.language, - primary: audio.main || video.main, - audio: audio.streams[i], - video: video.streams[j], + language: set.language || 'und', + primary: set.main, + audio: audio ? set.streams[i] : null, + video: video ? set.streams[i] : null, bandwidth: bandwidth, - drmInfos: drmInfos, + drmInfos: set.drmInfos, allowedByApplication: true, allowedByKeySystem: true, }; @@ -950,28 +971,7 @@ shaka.dash.DashParser.prototype.createVariants_ = variants.push(variant); } } - } - } else { - // Audio or video only variants - const set = audio || video; - for (let i = 0; i < set.streams.length; i++) { - bandwidth = set.streams[i].bandwidth || 0; - variant = { - id: this.globalId_++, - language: set.language || 'und', - primary: set.main, - audio: audio ? set.streams[i] : null, - video: video ? set.streams[i] : null, - bandwidth: bandwidth, - drmInfos: set.drmInfos, - allowedByApplication: true, - allowedByKeySystem: true, - }; - - variants.push(variant); - } - } -}; + }; /** @@ -1231,13 +1231,13 @@ shaka.dash.DashParser.prototype.parseRepresentation_ = function( streamInfo = { createSegmentIndex: Promise.resolve.bind(Promise), findSegmentPosition: - /** @return {?number} */ function(/** number */ time) { - if (time >= 0 && time < duration) { - return 1; - } else { - return null; - } - }, + /** @return {?number} */ function(/** number */ time) { + if (time >= 0 && time < duration) { + return 1; + } else { + return null; + } + }, getSegmentReference: /** @return {shaka.media.SegmentReference} */ function(/** number */ ref) { @@ -1307,7 +1307,7 @@ shaka.dash.DashParser.prototype.parseRepresentation_ = function( */ shaka.dash.DashParser.prototype.onUpdate_ = async function() { goog.asserts.assert(this.updatePeriod_ >= 0, - 'There should be an update period'); + 'There should be an update period'); shaka.log.info('Updating manifest...'); @@ -1319,7 +1319,7 @@ shaka.dash.DashParser.prototype.onUpdate_ = async function() { updateDelay = await this.requestManifest_(); } catch (error) { goog.asserts.assert(error instanceof shaka.util.Error, - 'Should only receive a Shaka error'); + 'Should only receive a Shaka error'); // Try updating again, but ensure we haven't been destroyed. if (this.playerInterface_) { @@ -1377,7 +1377,7 @@ shaka.dash.DashParser.prototype.setUpdateTimer_ = function(offset) { shaka.dash.DashParser.prototype.createFrame_ = function( elem, parent, baseUris) { goog.asserts.assert(parent || baseUris, - 'Must provide either parent or baseUris'); + 'Must provide either parent or baseUris'); const ManifestParserUtils = shaka.util.ManifestParserUtils; const XmlUtils = shaka.util.XmlUtils; parent = parent || /** @type {shaka.dash.DashParser.InheritanceFrame} */ ({ @@ -1462,65 +1462,65 @@ shaka.dash.DashParser.prototype.emsgSchemeIdUris_ = function( */ shaka.dash.DashParser.prototype.parseAudioChannels_ = function(audioChannelConfigs) { - for (let i = 0; i < audioChannelConfigs.length; ++i) { - const elem = audioChannelConfigs[i]; + for (let i = 0; i < audioChannelConfigs.length; ++i) { + const elem = audioChannelConfigs[i]; - const scheme = elem.getAttribute('schemeIdUri'); - if (!scheme) { - continue; - } - - const value = elem.getAttribute('value'); - if (!value) { - continue; - } - - switch (scheme) { - case 'urn:mpeg:dash:outputChannelPositionList:2012': - // A space-separated list of speaker positions, so the number of - // channels is the length of this list. - return value.trim().split(/ +/).length; - - case 'urn:mpeg:dash:23003:3:audio_channel_configuration:2011': - case 'urn:dts:dash:audio_channel_configuration:2012': { - // As far as we can tell, this is a number of channels. - const intValue = parseInt(value, 10); - if (!intValue) { // 0 or NaN - shaka.log.warning('Channel parsing failure! ' + - 'Ignoring scheme and value', scheme, value); + const scheme = elem.getAttribute('schemeIdUri'); + if (!scheme) { continue; } - return intValue; - } - case 'tag:dolby.com,2014:dash:audio_channel_configuration:2011': - case 'urn:dolby:dash:audio_channel_configuration:2011': { - // A hex-encoded 16-bit integer, in which each bit represents a channel. - let hexValue = parseInt(value, 16); - if (!hexValue) { // 0 or NaN - shaka.log.warning('Channel parsing failure! ' + - 'Ignoring scheme and value', scheme, value); + const value = elem.getAttribute('value'); + if (!value) { continue; } - // Count the 1-bits in hexValue. - let numBits = 0; - while (hexValue) { - if (hexValue & 1) { - ++numBits; + + switch (scheme) { + case 'urn:mpeg:dash:outputChannelPositionList:2012': + // A space-separated list of speaker positions, so the number of + // channels is the length of this list. + return value.trim().split(/ +/).length; + + case 'urn:mpeg:dash:23003:3:audio_channel_configuration:2011': + case 'urn:dts:dash:audio_channel_configuration:2012': { + // As far as we can tell, this is a number of channels. + const intValue = parseInt(value, 10); + if (!intValue) { // 0 or NaN + shaka.log.warning('Channel parsing failure! ' + + 'Ignoring scheme and value', scheme, value); + continue; + } + return intValue; } - hexValue >>= 1; + + case 'tag:dolby.com,2014:dash:audio_channel_configuration:2011': + case 'urn:dolby:dash:audio_channel_configuration:2011': { + // A hex-encoded 16-bit integer, in which each bit represents a channel. + let hexValue = parseInt(value, 16); + if (!hexValue) { // 0 or NaN + shaka.log.warning('Channel parsing failure! ' + + 'Ignoring scheme and value', scheme, value); + continue; + } + // Count the 1-bits in hexValue. + let numBits = 0; + while (hexValue) { + if (hexValue & 1) { + ++numBits; + } + hexValue >>= 1; + } + return numBits; + } + + default: + shaka.log.warning('Unrecognized audio channel scheme:', scheme, value); + continue; } - return numBits; } - default: - shaka.log.warning('Unrecognized audio channel scheme:', scheme, value); - continue; - } - } - - return null; -}; + return null; + }; /** @@ -1587,36 +1587,36 @@ shaka.dash.DashParser.prototype.verifyRepresentation_ = function(frame) { */ shaka.dash.DashParser.prototype.requestForTiming_ = async function(baseUris, uri, method) { - const requestUris = + const requestUris = shaka.util.ManifestParserUtils.resolveUris(baseUris, [uri]); - const request = shaka.net.NetworkingEngine.makeRequest( - requestUris, this.config_.retryParameters); - request.method = method; - const type = shaka.net.NetworkingEngine.RequestType.TIMING; + const request = shaka.net.NetworkingEngine.makeRequest( + requestUris, this.config_.retryParameters); + request.method = method; + const type = shaka.net.NetworkingEngine.RequestType.TIMING; - const operation = + const operation = this.playerInterface_.networkingEngine.request(type, request); - this.operationManager_.manage(operation); + this.operationManager_.manage(operation); - const response = await operation.promise; - let text; - if (method == 'HEAD') { - if (!response.headers || !response.headers['date']) { - shaka.log.warning('UTC timing response is missing', - 'expected date header'); - return 0; - } - text = response.headers['date']; - } else { - text = shaka.util.StringUtils.fromUTF8(response.data); - } - const date = Date.parse(text); - if (isNaN(date)) { - shaka.log.warning('Unable to parse date from UTC timing response'); - return 0; - } - return (date - Date.now()); -}; + const response = await operation.promise; + let text; + if (method == 'HEAD') { + if (!response.headers || !response.headers['date']) { + shaka.log.warning('UTC timing response is missing', + 'expected date header'); + return 0; + } + text = response.headers['date']; + } else { + text = shaka.util.StringUtils.fromUTF8(response.data); + } + const date = Date.parse(text); + if (isNaN(date)) { + shaka.log.warning('Unable to parse date from UTC timing response'); + return 0; + } + return (date - Date.now()); + }; /** diff --git a/lib/dash/mpd_utils.js b/lib/dash/mpd_utils.js index 6624c1168..c0434c532 100644 --- a/lib/dash/mpd_utils.js +++ b/lib/dash/mpd_utils.js @@ -140,7 +140,7 @@ shaka.dash.MpdUtils.fillUriTemplate = function( if (name == 'Time') { goog.asserts.assert(Math.abs(value - Math.round(value)) < 0.2, - 'Calculated $Time$ values must be close to integers'); + 'Calculated $Time$ values must be close to integers'); value = Math.round(value); } @@ -193,126 +193,126 @@ shaka.dash.MpdUtils.fillUriTemplate = function( */ shaka.dash.MpdUtils.createTimeline = function(segmentTimeline, timescale, unscaledPresentationTimeOffset, - periodDuration) { - goog.asserts.assert( - timescale > 0 && timescale < Infinity, - 'timescale must be a positive, finite integer'); - goog.asserts.assert(periodDuration > 0, - 'period duration must be a positive integer'); + periodDuration) { + goog.asserts.assert( + timescale > 0 && timescale < Infinity, + 'timescale must be a positive, finite integer'); + goog.asserts.assert(periodDuration > 0, + 'period duration must be a positive integer'); - // Alias. - const XmlUtils = shaka.util.XmlUtils; + // Alias. + const XmlUtils = shaka.util.XmlUtils; - const timePoints = XmlUtils.findChildren(segmentTimeline, 'S'); + const timePoints = XmlUtils.findChildren(segmentTimeline, 'S'); - /** @type {!Array.} */ - const timeline = []; - let lastEndTime = 0; + /** @type {!Array.} */ + const timeline = []; + let lastEndTime = 0; - for (let i = 0; i < timePoints.length; ++i) { - const timePoint = timePoints[i]; - let t = XmlUtils.parseAttr(timePoint, 't', XmlUtils.parseNonNegativeInt); - const d = XmlUtils.parseAttr(timePoint, 'd', XmlUtils.parseNonNegativeInt); - const r = XmlUtils.parseAttr(timePoint, 'r', XmlUtils.parseInt); + for (let i = 0; i < timePoints.length; ++i) { + const timePoint = timePoints[i]; + let t = XmlUtils.parseAttr(timePoint, 't', XmlUtils.parseNonNegativeInt); + const d = XmlUtils.parseAttr(timePoint, 'd', XmlUtils.parseNonNegativeInt); + const r = XmlUtils.parseAttr(timePoint, 'r', XmlUtils.parseInt); - // Adjust the start time to account for the presentation time offset. - if (t != null) { - t -= unscaledPresentationTimeOffset; - } + // Adjust the start time to account for the presentation time offset. + if (t != null) { + t -= unscaledPresentationTimeOffset; + } - if (!d) { - shaka.log.warning( - '"S" element must have a duration:', - 'ignoring the remaining "S" elements.', - timePoint); - return timeline; - } - - let startTime = t != null ? t : lastEndTime; - - let repeat = r || 0; - if (repeat < 0) { - if (i + 1 < timePoints.length) { - const nextTimePoint = timePoints[i + 1]; - const nextStartTime = XmlUtils.parseAttr( - nextTimePoint, 't', XmlUtils.parseNonNegativeInt); - if (nextStartTime == null) { + if (!d) { shaka.log.warning( - 'An "S" element cannot have a negative repeat', - 'if the next "S" element does not have a valid start time:', - 'ignoring the remaining "S" elements.', - timePoint); - return timeline; - } else if (startTime >= nextStartTime) { - shaka.log.warning( - 'An "S" element cannot have a negative repeat', - 'if its start time exceeds the next "S" element\'s start time:', + '"S" element must have a duration:', 'ignoring the remaining "S" elements.', timePoint); return timeline; } - repeat = Math.ceil((nextStartTime - startTime) / d) - 1; - } else { - if (periodDuration == Infinity) { - // The DASH spec. actually allows the last "S" element to have a - // negative repeat value even when the Period has an infinite - // duration. No one uses this feature and no one ever should, ever. - shaka.log.warning( - 'The last "S" element cannot have a negative repeat', - 'if the Period has an infinite duration:', - 'ignoring the last "S" element.', - timePoint); - return timeline; - } else if (startTime / timescale >= periodDuration) { - shaka.log.warning( - 'The last "S" element cannot have a negative repeat', - 'if its start time exceeds the Period\'s duration:', - 'igoring the last "S" element.', - timePoint); - return timeline; + + let startTime = t != null ? t : lastEndTime; + + let repeat = r || 0; + if (repeat < 0) { + if (i + 1 < timePoints.length) { + const nextTimePoint = timePoints[i + 1]; + const nextStartTime = XmlUtils.parseAttr( + nextTimePoint, 't', XmlUtils.parseNonNegativeInt); + if (nextStartTime == null) { + shaka.log.warning( + 'An "S" element cannot have a negative repeat', + 'if the next "S" element does not have a valid start time:', + 'ignoring the remaining "S" elements.', + timePoint); + return timeline; + } else if (startTime >= nextStartTime) { + shaka.log.warning( + 'An "S" element cannot have a negative repeat', + 'if its start time exceeds the next "S" element\'s start time:', + 'ignoring the remaining "S" elements.', + timePoint); + return timeline; + } + repeat = Math.ceil((nextStartTime - startTime) / d) - 1; + } else { + if (periodDuration == Infinity) { + // The DASH spec. actually allows the last "S" element to have a + // negative repeat value even when the Period has an infinite + // duration. No one uses this feature and no one ever should, ever. + shaka.log.warning( + 'The last "S" element cannot have a negative repeat', + 'if the Period has an infinite duration:', + 'ignoring the last "S" element.', + timePoint); + return timeline; + } else if (startTime / timescale >= periodDuration) { + shaka.log.warning( + 'The last "S" element cannot have a negative repeat', + 'if its start time exceeds the Period\'s duration:', + 'igoring the last "S" element.', + timePoint); + return timeline; + } + repeat = Math.ceil((periodDuration * timescale - startTime) / d) - 1; + } } - repeat = Math.ceil((periodDuration * timescale - startTime) / d) - 1; - } - } - // The end of the last segment may be before the start of the current - // segment (a gap) or after the start of the current segment (an overlap). - // If there is a gap/overlap then stretch/compress the end of the last - // segment to the start of the current segment. - // - // Note: it is possible to move the start of the current segment to the - // end of the last segment, but this would complicate the computation of - // the $Time$ placeholder later on. - if ((timeline.length > 0) && (startTime != lastEndTime)) { - const delta = startTime - lastEndTime; + // The end of the last segment may be before the start of the current + // segment (a gap) or after the start of the current segment (an overlap). + // If there is a gap/overlap then stretch/compress the end of the last + // segment to the start of the current segment. + // + // Note: it is possible to move the start of the current segment to the + // end of the last segment, but this would complicate the computation of + // the $Time$ placeholder later on. + if ((timeline.length > 0) && (startTime != lastEndTime)) { + const delta = startTime - lastEndTime; - if (Math.abs(delta / timescale) >= + if (Math.abs(delta / timescale) >= shaka.util.ManifestParserUtils.GAP_OVERLAP_TOLERANCE_SECONDS) { - shaka.log.warning( - 'SegmentTimeline contains a large gap/overlap:', - 'the content may have errors in it.', - timePoint); + shaka.log.warning( + 'SegmentTimeline contains a large gap/overlap:', + 'the content may have errors in it.', + timePoint); + } + + timeline[timeline.length - 1].end = startTime / timescale; + } + + for (let j = 0; j <= repeat; ++j) { + const endTime = startTime + d; + const item = { + start: startTime / timescale, + end: endTime / timescale, + unscaledStart: startTime, + }; + timeline.push(item); + + startTime = endTime; + lastEndTime = endTime; + } } - timeline[timeline.length - 1].end = startTime / timescale; - } - - for (let j = 0; j <= repeat; ++j) { - const endTime = startTime + d; - const item = { - start: startTime / timescale, - end: endTime / timescale, - unscaledStart: startTime, - }; - timeline.push(item); - - startTime = endTime; - lastEndTime = endTime; - } - } - - return timeline; -}; + return timeline; + }; /** @@ -347,7 +347,7 @@ shaka.dash.MpdUtils.parseSegmentInfo = function(context, callback) { MpdUtils.inheritAttribute(context, callback, 'startNumber'); const unscaledPresentationTimeOffset = Number(MpdUtils.inheritAttribute(context, callback, - 'presentationTimeOffset')) || 0; + 'presentationTimeOffset')) || 0; let startNumber = XmlUtils.parseNonNegativeInt(startNumberStr || ''); if (startNumberStr == null || startNumber == null) { startNumber = 1; @@ -449,99 +449,99 @@ shaka.dash.MpdUtils.inheritChild = function(context, callback, child) { */ shaka.dash.MpdUtils.handleXlinkInElement_ = function(element, retryParameters, failGracefully, baseUri, - networkingEngine, linkDepth) { - const MpdUtils = shaka.dash.MpdUtils; - const XmlUtils = shaka.util.XmlUtils; - const Error = shaka.util.Error; - const ManifestParserUtils = shaka.util.ManifestParserUtils; - const NS = MpdUtils.XlinkNamespaceUri_; + networkingEngine, linkDepth) { + const MpdUtils = shaka.dash.MpdUtils; + const XmlUtils = shaka.util.XmlUtils; + const Error = shaka.util.Error; + const ManifestParserUtils = shaka.util.ManifestParserUtils; + const NS = MpdUtils.XlinkNamespaceUri_; - const xlinkHref = XmlUtils.getAttributeNS(element, NS, 'href'); - const xlinkActuate = + const xlinkHref = XmlUtils.getAttributeNS(element, NS, 'href'); + const xlinkActuate = XmlUtils.getAttributeNS(element, NS, 'actuate') || 'onRequest'; - // Remove the xlink properties, so it won't download again - // when re-processed. - for (let i = 0; i < element.attributes.length; i++) { - const attribute = element.attributes[i]; - if (attribute.namespaceURI == NS) { - element.removeAttributeNS(attribute.namespaceURI, attribute.localName); - i -= 1; - } - } + // Remove the xlink properties, so it won't download again + // when re-processed. + for (let i = 0; i < element.attributes.length; i++) { + const attribute = element.attributes[i]; + if (attribute.namespaceURI == NS) { + element.removeAttributeNS(attribute.namespaceURI, attribute.localName); + i -= 1; + } + } - if (linkDepth >= 5) { - return shaka.util.AbortableOperation.failed(new Error( - Error.Severity.CRITICAL, Error.Category.MANIFEST, - Error.Code.DASH_XLINK_DEPTH_LIMIT)); - } + if (linkDepth >= 5) { + return shaka.util.AbortableOperation.failed(new Error( + Error.Severity.CRITICAL, Error.Category.MANIFEST, + Error.Code.DASH_XLINK_DEPTH_LIMIT)); + } - if (xlinkActuate != 'onLoad') { - // Only xlink:actuate="onLoad" is supported. - // When no value is specified, the assumed value is "onRequest". - return shaka.util.AbortableOperation.failed(new Error( - Error.Severity.CRITICAL, Error.Category.MANIFEST, - Error.Code.DASH_UNSUPPORTED_XLINK_ACTUATE)); - } + if (xlinkActuate != 'onLoad') { + // Only xlink:actuate="onLoad" is supported. + // When no value is specified, the assumed value is "onRequest". + return shaka.util.AbortableOperation.failed(new Error( + Error.Severity.CRITICAL, Error.Category.MANIFEST, + Error.Code.DASH_UNSUPPORTED_XLINK_ACTUATE)); + } - // Resolve the xlink href, in case it's a relative URL. - const uris = ManifestParserUtils.resolveUris([baseUri], [xlinkHref]); + // Resolve the xlink href, in case it's a relative URL. + const uris = ManifestParserUtils.resolveUris([baseUri], [xlinkHref]); - // Load in the linked elements. - const requestType = shaka.net.NetworkingEngine.RequestType.MANIFEST; - const request = shaka.net.NetworkingEngine.makeRequest( - uris, retryParameters); + // Load in the linked elements. + const requestType = shaka.net.NetworkingEngine.RequestType.MANIFEST; + const request = shaka.net.NetworkingEngine.makeRequest( + uris, retryParameters); - const requestOperation = networkingEngine.request(requestType, request); - // The interface is abstract, but we know it was implemented with the - // more capable internal class. - goog.asserts.assert(requestOperation instanceof shaka.util.AbortableOperation, - 'Unexpected implementation of IAbortableOperation!'); - // Satisfy the compiler with a cast. - const networkOperation = + const requestOperation = networkingEngine.request(requestType, request); + // The interface is abstract, but we know it was implemented with the + // more capable internal class. + goog.asserts.assert(requestOperation instanceof shaka.util.AbortableOperation, + 'Unexpected implementation of IAbortableOperation!'); + // Satisfy the compiler with a cast. + const networkOperation = /** @type {!shaka.util.AbortableOperation.} */( requestOperation); - // Chain onto that operation. - return networkOperation.chain((response) => { - // This only supports the case where the loaded xml has a single - // top-level element. If there are multiple roots, it will be rejected. - const rootElem = + // Chain onto that operation. + return networkOperation.chain((response) => { + // This only supports the case where the loaded xml has a single + // top-level element. If there are multiple roots, it will be rejected. + const rootElem = shaka.util.XmlUtils.parseXml(response.data, element.tagName); - if (!rootElem) { - // It was not valid XML. - return shaka.util.AbortableOperation.failed(new Error( - Error.Severity.CRITICAL, Error.Category.MANIFEST, - Error.Code.DASH_INVALID_XML, xlinkHref)); - } + if (!rootElem) { + // It was not valid XML. + return shaka.util.AbortableOperation.failed(new Error( + Error.Severity.CRITICAL, Error.Category.MANIFEST, + Error.Code.DASH_INVALID_XML, xlinkHref)); + } - // Now that there is no other possibility of the process erroring, - // the element can be changed further. + // Now that there is no other possibility of the process erroring, + // the element can be changed further. - // Remove the current contents of the node. - while (element.childNodes.length) { - element.removeChild(element.childNodes[0]); - } + // Remove the current contents of the node. + while (element.childNodes.length) { + element.removeChild(element.childNodes[0]); + } - // Move the children of the loaded xml into the current element. - while (rootElem.childNodes.length) { - const child = rootElem.childNodes[0]; - rootElem.removeChild(child); - element.appendChild(child); - } + // Move the children of the loaded xml into the current element. + while (rootElem.childNodes.length) { + const child = rootElem.childNodes[0]; + rootElem.removeChild(child); + element.appendChild(child); + } - // Move the attributes of the loaded xml into the current element. - for (let i = 0; i < rootElem.attributes.length; i++) { - const attribute = rootElem.attributes[i].nodeName; - const attributeValue = rootElem.getAttribute(attribute); - element.setAttribute(attribute, attributeValue); - } + // Move the attributes of the loaded xml into the current element. + for (let i = 0; i < rootElem.attributes.length; i++) { + const attribute = rootElem.attributes[i].nodeName; + const attributeValue = rootElem.getAttribute(attribute); + element.setAttribute(attribute, attributeValue); + } - return shaka.dash.MpdUtils.processXlinks( - element, retryParameters, failGracefully, uris[0], networkingEngine, - linkDepth + 1); - }); -}; + return shaka.dash.MpdUtils.processXlinks( + element, retryParameters, failGracefully, uris[0], networkingEngine, + linkDepth + 1); + }); + }; /** @@ -558,53 +558,53 @@ shaka.dash.MpdUtils.handleXlinkInElement_ = */ shaka.dash.MpdUtils.processXlinks = function(element, retryParameters, failGracefully, baseUri, - networkingEngine, linkDepth = 0) { - const MpdUtils = shaka.dash.MpdUtils; - const XmlUtils = shaka.util.XmlUtils; - const NS = MpdUtils.XlinkNamespaceUri_; + networkingEngine, linkDepth = 0) { + const MpdUtils = shaka.dash.MpdUtils; + const XmlUtils = shaka.util.XmlUtils; + const NS = MpdUtils.XlinkNamespaceUri_; - if (XmlUtils.getAttributeNS(element, NS, 'href')) { - let handled = MpdUtils.handleXlinkInElement_( - element, retryParameters, failGracefully, baseUri, - networkingEngine, linkDepth); - if (failGracefully) { - // Catch any error and go on. - handled = handled.chain(undefined, (error) => { - // handleXlinkInElement_ strips the xlink properties off of the element - // even if it fails, so calling processXlinks again will handle whatever - // contents the element natively has. - return MpdUtils.processXlinks(element, retryParameters, failGracefully, - baseUri, networkingEngine, - linkDepth); - }); - } - return handled; - } - - const childOperations = []; - for (let i = 0; i < element.childNodes.length; i++) { - const child = element.childNodes[i]; - if (child instanceof Element) { - const resolveToZeroString = 'urn:mpeg:dash:resolve-to-zero:2013'; - if (XmlUtils.getAttributeNS(child, NS, 'href') == resolveToZeroString) { - // This is a 'resolve to zero' code; it means the element should - // be removed, as specified by the mpeg-dash rules for xlink. - element.removeChild(child); - i -= 1; - } else if (child.tagName != 'SegmentTimeline') { - // Don't recurse into a SegmentTimeline since xlink attributes aren't - // valid in there and looking at each segment can take a long time with - // larger manifests. - - // Replace the child with its processed form. - childOperations.push(shaka.dash.MpdUtils.processXlinks( - /** @type {!Element} */ (child), retryParameters, failGracefully, - baseUri, networkingEngine, linkDepth)); + if (XmlUtils.getAttributeNS(element, NS, 'href')) { + let handled = MpdUtils.handleXlinkInElement_( + element, retryParameters, failGracefully, baseUri, + networkingEngine, linkDepth); + if (failGracefully) { + // Catch any error and go on. + handled = handled.chain(undefined, (error) => { + // handleXlinkInElement_ strips the xlink properties off of the element + // even if it fails, so calling processXlinks again will handle whatever + // contents the element natively has. + return MpdUtils.processXlinks(element, retryParameters, failGracefully, + baseUri, networkingEngine, + linkDepth); + }); + } + return handled; } - } - } - return shaka.util.AbortableOperation.all(childOperations).chain(() => { - return element; - }); -}; + const childOperations = []; + for (let i = 0; i < element.childNodes.length; i++) { + const child = element.childNodes[i]; + if (child instanceof Element) { + const resolveToZeroString = 'urn:mpeg:dash:resolve-to-zero:2013'; + if (XmlUtils.getAttributeNS(child, NS, 'href') == resolveToZeroString) { + // This is a 'resolve to zero' code; it means the element should + // be removed, as specified by the mpeg-dash rules for xlink. + element.removeChild(child); + i -= 1; + } else if (child.tagName != 'SegmentTimeline') { + // Don't recurse into a SegmentTimeline since xlink attributes aren't + // valid in there and looking at each segment can take a long time with + // larger manifests. + + // Replace the child with its processed form. + childOperations.push(shaka.dash.MpdUtils.processXlinks( + /** @type {!Element} */ (child), retryParameters, failGracefully, + baseUri, networkingEngine, linkDepth)); + } + } + } + + return shaka.util.AbortableOperation.all(childOperations).chain(() => { + return element; + }); + }; diff --git a/lib/dash/segment_base.js b/lib/dash/segment_base.js index 193e74c2e..1194994c7 100644 --- a/lib/dash/segment_base.js +++ b/lib/dash/segment_base.js @@ -84,7 +84,7 @@ shaka.dash.SegmentBase.createInitSegment = function(context, callback) { */ shaka.dash.SegmentBase.createStream = function(context, requestInitSegment) { goog.asserts.assert(context.representation.segmentBase, - 'Should only be called with SegmentBase'); + 'Should only be called with SegmentBase'); // Since SegmentBase does not need updates, simply treat any call as // the initial parse. const MpdUtils = shaka.dash.MpdUtils; @@ -174,7 +174,7 @@ shaka.dash.SegmentBase.createSegmentIndexFromUris = function( // Since containers are never updated, we don't need to store the // segmentIndex in the map. goog.asserts.assert(!segmentIndex, - 'Should not call createSegmentIndex twice'); + 'Should not call createSegmentIndex twice'); segmentIndex = new shaka.media.SegmentIndex(references); if (fitLast) { diff --git a/lib/dash/segment_list.js b/lib/dash/segment_list.js index bea4307aa..7e6841bfc 100644 --- a/lib/dash/segment_list.js +++ b/lib/dash/segment_list.js @@ -44,7 +44,7 @@ goog.require('shaka.util.XmlUtils'); */ shaka.dash.SegmentList.createStream = function(context, segmentIndexMap) { goog.asserts.assert(context.representation.segmentList, - 'Should only be called with SegmentList'); + 'Should only be called with SegmentList'); const SegmentList = shaka.dash.SegmentList; const init = shaka.dash.SegmentBase.createInitSegment( diff --git a/lib/dash/segment_template.js b/lib/dash/segment_template.js index d0f57f6b1..77ccd6bdf 100644 --- a/lib/dash/segment_template.js +++ b/lib/dash/segment_template.js @@ -47,7 +47,7 @@ goog.require('shaka.util.ManifestParserUtils'); shaka.dash.SegmentTemplate.createStream = function( context, requestInitSegment, segmentIndexMap, isUpdate) { goog.asserts.assert(context.representation.segmentTemplate, - 'Should only be called with SegmentTemplate'); + 'Should only be called with SegmentTemplate'); const SegmentTemplate = shaka.dash.SegmentTemplate; const init = SegmentTemplate.createInitSegment_(context); @@ -65,7 +65,7 @@ shaka.dash.SegmentTemplate.createStream = function( context.presentationTimeline.notifyMaxSegmentDuration( info.segmentDuration); context.presentationTimeline.notifyMinSegmentStartTime( - context.periodInfo.start); + context.periodInfo.start); } segmentIndexFunctions = SegmentTemplate.createFromDuration_(context, info); } else { @@ -321,7 +321,7 @@ shaka.dash.SegmentTemplate.createFromIndexTemplate_ = function( */ shaka.dash.SegmentTemplate.createFromDuration_ = function(context, info) { goog.asserts.assert(info.mediaTemplate, - 'There should be a media template with duration'); + 'There should be a media template with duration'); const MpdUtils = shaka.dash.MpdUtils; const ManifestParserUtils = shaka.util.ManifestParserUtils; @@ -389,7 +389,7 @@ shaka.dash.SegmentTemplate.createFromDuration_ = function(context, info) { */ shaka.dash.SegmentTemplate.createFromTimeline_ = function(context, info) { goog.asserts.assert(info.mediaTemplate, - 'There should be a media template with a timeline'); + 'There should be a media template with a timeline'); const MpdUtils = shaka.dash.MpdUtils; const ManifestParserUtils = shaka.util.ManifestParserUtils; @@ -408,14 +408,14 @@ shaka.dash.SegmentTemplate.createFromTimeline_ = function(context, info) { const timeReplacement = unscaledStart + info.unscaledPresentationTimeOffset; const createUris = (function( - template, repId, bandwidth, baseUris, segmentId, time) { - const mediaUri = MpdUtils.fillUriTemplate( - template, repId, segmentId, bandwidth, time); - return ManifestParserUtils.resolveUris(baseUris, [mediaUri]) - .map((g) => { return g.toString(); }); - }.bind(null, info.mediaTemplate, context.representation.id, - context.bandwidth || null, context.representation.baseUris, - segmentReplacement, timeReplacement)); + template, repId, bandwidth, baseUris, segmentId, time) { + const mediaUri = MpdUtils.fillUriTemplate( + template, repId, segmentId, bandwidth, time); + return ManifestParserUtils.resolveUris(baseUris, [mediaUri]) + .map((g) => { return g.toString(); }); + }.bind(null, info.mediaTemplate, context.representation.id, + context.bandwidth || null, context.representation.baseUris, + segmentReplacement, timeReplacement)); references.push(new shaka.media.SegmentReference( segmentReplacement, start, end, createUris, 0, null)); diff --git a/lib/hls/hls_classes.js b/lib/hls/hls_classes.js index 407571ddf..cd1855dde 100644 --- a/lib/hls/hls_classes.js +++ b/lib/hls/hls_classes.js @@ -175,7 +175,7 @@ shaka.hls.Tag.prototype.getAttribute = function(name) { }); goog.asserts.assert(attributes.length < 2, - 'A tag should not have multiple attributes ' + + 'A tag should not have multiple attributes ' + 'with the same name!'); if (attributes.length) { diff --git a/lib/hls/hls_parser.js b/lib/hls/hls_parser.js index 0ace029ed..860a9eaf2 100644 --- a/lib/hls/hls_parser.js +++ b/lib/hls/hls_parser.js @@ -326,11 +326,11 @@ shaka.hls.HlsParser.prototype.updateStream_ = async function(streamInfo) { const stream = streamInfo.stream; const segments = await this.createSegments_( - streamInfo.verbatimMediaPlaylistUri, - playlist, - startPosition, - stream.mimeType, - stream.codecs); + streamInfo.verbatimMediaPlaylistUri, + playlist, + startPosition, + stream.mimeType, + stream.codecs); streamInfo.segmentIndex.replace(segments); @@ -431,13 +431,13 @@ shaka.hls.HlsParser.prototype.parseManifest_ = async function(data) { // This assert is our own sanity check. goog.asserts.assert(this.presentationTimeline_ == null, - 'Presentation timeline created early!'); + 'Presentation timeline created early!'); this.createPresentationTimeline_(maxLastTimestamp); // This assert satisfies the compiler that it is not null for the rest of // the method. goog.asserts.assert(this.presentationTimeline_, - 'Presentation timeline not created!'); + 'Presentation timeline not created!'); if (this.isLive_()) { // The HLS spec (RFC 8216) states in 6.3.4: @@ -476,7 +476,7 @@ shaka.hls.HlsParser.prototype.parseManifest_ = async function(data) { } if (offset) { shaka.log.debug('Offsetting live streams by', offset, - 'to compensate for rollover'); + 'to compensate for rollover'); for (const streamInfo of this.uriToStreamInfosMap_.values()) { if (streamInfo.minTimestamp < rolloverSeconds) { @@ -580,205 +580,205 @@ shaka.hls.HlsParser.prototype.createPeriod_ = async function(playlist) { */ shaka.hls.HlsParser.prototype.createVariantsForTag_ = async function(tag, playlist) { - goog.asserts.assert(tag.name == 'EXT-X-STREAM-INF', - 'Should only be called on variant tags!'); - const ContentType = shaka.util.ManifestParserUtils.ContentType; - const Utils = shaka.hls.Utils; + goog.asserts.assert(tag.name == 'EXT-X-STREAM-INF', + 'Should only be called on variant tags!'); + const ContentType = shaka.util.ManifestParserUtils.ContentType; + const Utils = shaka.hls.Utils; - // These are the default codecs to assume if none are specified. - // - // The video codec is H.264, with baseline profile and level 3.0. - // http://blog.pearce.org.nz/2013/11/what-does-h264avc1-codecs-parameters.html - // - // The audio codec is "low-complexity" AAC. - const defaultCodecs = 'avc1.42E01E,mp4a.40.2'; + // These are the default codecs to assume if none are specified. + // + // The video codec is H.264, with baseline profile and level 3.0. + // http://blog.pearce.org.nz/2013/11/what-does-h264avc1-codecs-parameters.html + // + // The audio codec is "low-complexity" AAC. + const defaultCodecs = 'avc1.42E01E,mp4a.40.2'; - const codecsString = tag.getAttributeValue('CODECS', defaultCodecs); - // Strip out internal whitespace while splitting on commas: - /** @type {!Array.} */ - let codecs = + const codecsString = tag.getAttributeValue('CODECS', defaultCodecs); + // Strip out internal whitespace while splitting on commas: + /** @type {!Array.} */ + let codecs = shaka.hls.HlsParser.filterDuplicateCodecs_(codecsString.split(/\s*,\s*/)); - const resolutionAttr = tag.getAttribute('RESOLUTION'); - let width = null; - let height = null; - const frameRate = tag.getAttributeValue('FRAME-RATE'); - const bandwidth = + const resolutionAttr = tag.getAttribute('RESOLUTION'); + let width = null; + let height = null; + const frameRate = tag.getAttributeValue('FRAME-RATE'); + const bandwidth = Number(shaka.hls.HlsParser.getRequiredAttributeValue_(tag, 'BANDWIDTH')); - if (resolutionAttr) { - const resBlocks = resolutionAttr.value.split('x'); - width = resBlocks[0]; - height = resBlocks[1]; - } - - // After filtering, this is a list of the media tags we will process to - // combine with the variant tag (EXT-X-STREAM-INF) we are working on. - let mediaTags = Utils.filterTagsByName(playlist.tags, 'EXT-X-MEDIA'); - - // Do not create stream info from closed captions media tags, which are - // embedded in video streams. - mediaTags = mediaTags.filter((tag) => { - const type = shaka.hls.HlsParser.getRequiredAttributeValue_(tag, 'TYPE'); - return type != 'CLOSED-CAPTIONS'; - }); - - // AUDIO or VIDEO tags without a URI attribute are valid. - // If there is no uri, it means that audio/video is embedded in the - // stream described by the Variant tag. - // Do not create stream from AUDIO/VIDEO EXT-X-MEDIA tags without URI - mediaTags = mediaTags.filter((tag) => { - const uri = tag.getAttributeValue('URI') || ''; - const type = tag.getAttributeValue('TYPE') || ''; - return type == 'SUBTITLES' || uri != ''; - }); - - const audioGroupId = tag.getAttributeValue('AUDIO'); - const videoGroupId = tag.getAttributeValue('VIDEO'); - goog.asserts.assert(audioGroupId == null || videoGroupId == null, - 'Unexpected: both video and audio described by media tags!'); - - // Find any associated audio or video groups and create streams for them. - if (audioGroupId) { - mediaTags = Utils.findMediaTags(mediaTags, 'AUDIO', audioGroupId); - } else if (videoGroupId) { - mediaTags = Utils.findMediaTags(mediaTags, 'VIDEO', videoGroupId); - } - - // There may be a codec string for the text stream. We should identify it, - // add it to the appropriate stream, then strip it out of the variant to - // avoid confusing our multiplex detection below. - const textCodecs = this.guessCodecsSafe_(ContentType.TEXT, codecs); - if (textCodecs) { - // We found a text codec in the list, so look for an associated text stream. - const subGroupId = tag.getAttributeValue('SUBTITLES'); - if (subGroupId) { - const textTags = Utils.findMediaTags(mediaTags, 'SUBTITLES', subGroupId); - goog.asserts.assert(textTags.length == 1, - 'Exactly one text tag expected!'); - if (textTags.length) { - // We found a text codec and text stream, so make sure the codec is - // attached to the stream. - const textStreamInfo = - this.mediaTagsToStreamInfosMap_.get(textTags[0].id); - textStreamInfo.stream.codecs = textCodecs; + if (resolutionAttr) { + const resBlocks = resolutionAttr.value.split('x'); + width = resBlocks[0]; + height = resBlocks[1]; } - } - // Remove this entry from the list of codecs that belong to audio/video. - shaka.util.ArrayUtils.remove(codecs, textCodecs); - } + // After filtering, this is a list of the media tags we will process to + // combine with the variant tag (EXT-X-STREAM-INF) we are working on. + let mediaTags = Utils.filterTagsByName(playlist.tags, 'EXT-X-MEDIA'); - const promises = mediaTags.map((tag) => { - return this.createStreamInfoFromMediaTag_(tag, codecs); - }); + // Do not create stream info from closed captions media tags, which are + // embedded in video streams. + mediaTags = mediaTags.filter((tag) => { + const type = shaka.hls.HlsParser.getRequiredAttributeValue_(tag, 'TYPE'); + return type != 'CLOSED-CAPTIONS'; + }); - let audioStreamInfos = []; - let videoStreamInfos = []; + // AUDIO or VIDEO tags without a URI attribute are valid. + // If there is no uri, it means that audio/video is embedded in the + // stream described by the Variant tag. + // Do not create stream from AUDIO/VIDEO EXT-X-MEDIA tags without URI + mediaTags = mediaTags.filter((tag) => { + const uri = tag.getAttributeValue('URI') || ''; + const type = tag.getAttributeValue('TYPE') || ''; + return type == 'SUBTITLES' || uri != ''; + }); - let streamInfo; - let data = await Promise.all(promises); - // Filter out null streamInfo. - data = data.filter((info) => info != null); - if (audioGroupId) { - audioStreamInfos = data; - } else if (videoGroupId) { - videoStreamInfos = data; - } + const audioGroupId = tag.getAttributeValue('AUDIO'); + const videoGroupId = tag.getAttributeValue('VIDEO'); + goog.asserts.assert(audioGroupId == null || videoGroupId == null, + 'Unexpected: both video and audio described by media tags!'); - // Make an educated guess about the stream type. - shaka.log.debug('Guessing stream type for', tag.toString()); - let type; - let ignoreStream = false; - if (!audioStreamInfos.length && !videoStreamInfos.length) { - // There are no associated streams. This is either an audio-only stream, - // a video-only stream, or a multiplexed stream. + // Find any associated audio or video groups and create streams for them. + if (audioGroupId) { + mediaTags = Utils.findMediaTags(mediaTags, 'AUDIO', audioGroupId); + } else if (videoGroupId) { + mediaTags = Utils.findMediaTags(mediaTags, 'VIDEO', videoGroupId); + } - if (codecs.length == 1) { - // There is only one codec, so it shouldn't be multiplexed. + // There may be a codec string for the text stream. We should identify it, + // add it to the appropriate stream, then strip it out of the variant to + // avoid confusing our multiplex detection below. + const textCodecs = this.guessCodecsSafe_(ContentType.TEXT, codecs); + if (textCodecs) { + // We found a text codec in the list, so look for an associated text stream. + const subGroupId = tag.getAttributeValue('SUBTITLES'); + if (subGroupId) { + const textTags = Utils.findMediaTags(mediaTags, 'SUBTITLES', subGroupId); + goog.asserts.assert(textTags.length == 1, + 'Exactly one text tag expected!'); + if (textTags.length) { + // We found a text codec and text stream, so make sure the codec is + // attached to the stream. + const textStreamInfo = + this.mediaTagsToStreamInfosMap_.get(textTags[0].id); + textStreamInfo.stream.codecs = textCodecs; + } + } - const videoCodecs = this.guessCodecsSafe_(ContentType.VIDEO, codecs); - if (resolutionAttr || frameRate || videoCodecs) { - // Assume video-only. - shaka.log.debug('Guessing video-only.'); - type = ContentType.VIDEO; + // Remove this entry from the list of codecs that belong to audio/video. + shaka.util.ArrayUtils.remove(codecs, textCodecs); + } + + const promises = mediaTags.map((tag) => { + return this.createStreamInfoFromMediaTag_(tag, codecs); + }); + + let audioStreamInfos = []; + let videoStreamInfos = []; + + let streamInfo; + let data = await Promise.all(promises); + // Filter out null streamInfo. + data = data.filter((info) => info != null); + if (audioGroupId) { + audioStreamInfos = data; + } else if (videoGroupId) { + videoStreamInfos = data; + } + + // Make an educated guess about the stream type. + shaka.log.debug('Guessing stream type for', tag.toString()); + let type; + let ignoreStream = false; + if (!audioStreamInfos.length && !videoStreamInfos.length) { + // There are no associated streams. This is either an audio-only stream, + // a video-only stream, or a multiplexed stream. + + if (codecs.length == 1) { + // There is only one codec, so it shouldn't be multiplexed. + + const videoCodecs = this.guessCodecsSafe_(ContentType.VIDEO, codecs); + if (resolutionAttr || frameRate || videoCodecs) { + // Assume video-only. + shaka.log.debug('Guessing video-only.'); + type = ContentType.VIDEO; + } else { + // Assume audio-only. + shaka.log.debug('Guessing audio-only.'); + type = ContentType.AUDIO; + } + } else { + // There are multiple codecs, so assume multiplexed content. + // Note that the default used when CODECS is missing assumes multiple + // (and therefore multiplexed). + // Recombine the codec strings into one so that MediaSource isn't + // lied to later. (That would trigger an error in Chrome.) + shaka.log.debug('Guessing multiplexed audio+video.'); + type = ContentType.VIDEO; + codecs = [codecs.join(',')]; + } + } else if (audioStreamInfos.length) { + const streamURI = + shaka.hls.HlsParser.getRequiredAttributeValue_(tag, 'URI'); + const firstAudioStreamURI = audioStreamInfos[0].verbatimMediaPlaylistUri; + if (streamURI == firstAudioStreamURI) { + // The Microsoft HLS manifest generators will make audio-only variants + // that link to their URI both directly and through an audio tag. + // In that case, ignore the local URI and use the version in the + // AUDIO tag, so you inherit its language. + // As an example, see the manifest linked in issue #860. + shaka.log.debug('Guessing audio-only.'); + type = ContentType.AUDIO; + ignoreStream = true; + } else { + // There are associated audio streams. Assume this is video. + shaka.log.debug('Guessing video.'); + type = ContentType.VIDEO; + } } else { - // Assume audio-only. - shaka.log.debug('Guessing audio-only.'); + // There are associated video streams. Assume this is audio. + goog.asserts.assert(videoStreamInfos.length, + 'No video streams! This should have been handled already!'); + shaka.log.debug('Guessing audio.'); type = ContentType.AUDIO; } - } else { - // There are multiple codecs, so assume multiplexed content. - // Note that the default used when CODECS is missing assumes multiple - // (and therefore multiplexed). - // Recombine the codec strings into one so that MediaSource isn't - // lied to later. (That would trigger an error in Chrome.) - shaka.log.debug('Guessing multiplexed audio+video.'); - type = ContentType.VIDEO; - codecs = [codecs.join(',')]; - } - } else if (audioStreamInfos.length) { - const streamURI = - shaka.hls.HlsParser.getRequiredAttributeValue_(tag, 'URI'); - const firstAudioStreamURI = audioStreamInfos[0].verbatimMediaPlaylistUri; - if (streamURI == firstAudioStreamURI) { - // The Microsoft HLS manifest generators will make audio-only variants - // that link to their URI both directly and through an audio tag. - // In that case, ignore the local URI and use the version in the - // AUDIO tag, so you inherit its language. - // As an example, see the manifest linked in issue #860. - shaka.log.debug('Guessing audio-only.'); - type = ContentType.AUDIO; - ignoreStream = true; - } else { - // There are associated audio streams. Assume this is video. - shaka.log.debug('Guessing video.'); - type = ContentType.VIDEO; - } - } else { - // There are associated video streams. Assume this is audio. - goog.asserts.assert(videoStreamInfos.length, - 'No video streams! This should have been handled already!'); - shaka.log.debug('Guessing audio.'); - type = ContentType.AUDIO; - } - goog.asserts.assert(type, 'Type should have been set by now!'); - if (!ignoreStream) { - streamInfo = + goog.asserts.assert(type, 'Type should have been set by now!'); + if (!ignoreStream) { + streamInfo = await this.createStreamInfoFromVariantTag_(tag, codecs, type); - } + } - if (streamInfo) { - if (streamInfo.stream.type == ContentType.AUDIO) { - audioStreamInfos = [streamInfo]; - } else { - videoStreamInfos = [streamInfo]; - } - } else if (streamInfo === null) { // Triple-equals to distinguish undefined - // We do not support AES-128 encryption with HLS yet. If the streamInfo is - // null because of AES-128 encryption, do not create variants for that. - shaka.log.debug('streamInfo is null'); - return []; - } + if (streamInfo) { + if (streamInfo.stream.type == ContentType.AUDIO) { + audioStreamInfos = [streamInfo]; + } else { + videoStreamInfos = [streamInfo]; + } + } else if (streamInfo === null) { // Triple-equals to distinguish undefined + // We do not support AES-128 encryption with HLS yet. If the streamInfo is + // null because of AES-128 encryption, do not create variants for that. + shaka.log.debug('streamInfo is null'); + return []; + } - goog.asserts.assert(videoStreamInfos.length || audioStreamInfos.length, - 'We should have created a stream!'); + goog.asserts.assert(videoStreamInfos.length || audioStreamInfos.length, + 'We should have created a stream!'); - if (videoStreamInfos) { - this.filterLegacyCodecs_(videoStreamInfos); - } - if (audioStreamInfos) { - this.filterLegacyCodecs_(audioStreamInfos); - } + if (videoStreamInfos) { + this.filterLegacyCodecs_(videoStreamInfos); + } + if (audioStreamInfos) { + this.filterLegacyCodecs_(audioStreamInfos); + } - return this.createVariants_( - audioStreamInfos, - videoStreamInfos, - bandwidth, - width, - height, - frameRate); -}; + return this.createVariants_( + audioStreamInfos, + videoStreamInfos, + bandwidth, + width, + height, + frameRate); + }; /** @@ -813,64 +813,64 @@ shaka.hls.HlsParser.prototype.filterLegacyCodecs_ = function(streamInfos) { */ shaka.hls.HlsParser.prototype.createVariants_ = function(audioInfos, videoInfos, bandwidth, width, height, frameRate) { - const DrmEngine = shaka.media.DrmEngine; + const DrmEngine = shaka.media.DrmEngine; - videoInfos.forEach((info) => { - this.addVideoAttributes_(info.stream, width, height, frameRate); - }); + videoInfos.forEach((info) => { + this.addVideoAttributes_(info.stream, width, height, frameRate); + }); - // In case of audio-only or video-only content, we create an array of - // one item containing a null. This way, the double-loop works for all - // kinds of content. - // NOTE: we currently don't have support for audio-only content. - if (!audioInfos.length) { - audioInfos = [null]; - } - if (!videoInfos.length) { - videoInfos = [null]; - } + // In case of audio-only or video-only content, we create an array of + // one item containing a null. This way, the double-loop works for all + // kinds of content. + // NOTE: we currently don't have support for audio-only content. + if (!audioInfos.length) { + audioInfos = [null]; + } + if (!videoInfos.length) { + videoInfos = [null]; + } - const variants = []; - for (const audioInfo of audioInfos) { - for (const videoInfo of videoInfos) { - const audioStream = audioInfo ? audioInfo.stream : null; - const videoStream = videoInfo ? videoInfo.stream : null; - const audioDrmInfos = audioInfo ? audioInfo.drmInfos : null; - const videoDrmInfos = videoInfo ? videoInfo.drmInfos : null; - const videoStreamUri = + const variants = []; + for (const audioInfo of audioInfos) { + for (const videoInfo of videoInfos) { + const audioStream = audioInfo ? audioInfo.stream : null; + const videoStream = videoInfo ? videoInfo.stream : null; + const audioDrmInfos = audioInfo ? audioInfo.drmInfos : null; + const videoDrmInfos = videoInfo ? videoInfo.drmInfos : null; + const videoStreamUri = videoInfo ? videoInfo.verbatimMediaPlaylistUri : ''; - const audioStreamUri = + const audioStreamUri = audioInfo ? audioInfo.verbatimMediaPlaylistUri : ''; - const variantUriKey = videoStreamUri + ' - ' + audioStreamUri; + const variantUriKey = videoStreamUri + ' - ' + audioStreamUri; - let drmInfos; - if (audioStream && videoStream) { - if (DrmEngine.areDrmCompatible(audioDrmInfos, videoDrmInfos)) { - drmInfos = DrmEngine.getCommonDrmInfos(audioDrmInfos, videoDrmInfos); - } else { - shaka.log.warning('Incompatible DRM info in HLS variant. Skipping.'); - continue; + let drmInfos; + if (audioStream && videoStream) { + if (DrmEngine.areDrmCompatible(audioDrmInfos, videoDrmInfos)) { + drmInfos = DrmEngine.getCommonDrmInfos(audioDrmInfos, videoDrmInfos); + } else { + shaka.log.warning('Incompatible DRM info in HLS variant. Skipping.'); + continue; + } + } else if (audioStream) { + drmInfos = audioDrmInfos; + } else if (videoStream) { + drmInfos = videoDrmInfos; + } + + if (this.variantUriSet_.has(variantUriKey)) { + // This happens when two variants only differ in their text streams. + shaka.log.debug('Skipping variant which only differs in text streams.'); + continue; + } + + const variant = this.createVariant_( + audioStream, videoStream, bandwidth, drmInfos); + variants.push(variant); + this.variantUriSet_.add(variantUriKey); } - } else if (audioStream) { - drmInfos = audioDrmInfos; - } else if (videoStream) { - drmInfos = videoDrmInfos; } - - if (this.variantUriSet_.has(variantUriKey)) { - // This happens when two variants only differ in their text streams. - shaka.log.debug('Skipping variant which only differs in text streams.'); - continue; - } - - const variant = this.createVariant_( - audioStream, videoStream, bandwidth, drmInfos); - variants.push(variant); - this.variantUriSet_.add(variantUriKey); - } - } - return variants; -}; + return variants; + }; /** @@ -883,27 +883,27 @@ shaka.hls.HlsParser.prototype.createVariants_ = */ shaka.hls.HlsParser.prototype.createVariant_ = function(audio, video, bandwidth, drmInfos) { - const ContentType = shaka.util.ManifestParserUtils.ContentType; + const ContentType = shaka.util.ManifestParserUtils.ContentType; - // Since both audio and video are of the same type, this assertion will catch - // certain mistakes at runtime that the compiler would miss. - goog.asserts.assert(!audio || audio.type == ContentType.AUDIO, - 'Audio parameter mismatch!'); - goog.asserts.assert(!video || video.type == ContentType.VIDEO, - 'Video parameter mismatch!'); + // Since both audio and video are of the same type, this assertion will catch + // certain mistakes at runtime that the compiler would miss. + goog.asserts.assert(!audio || audio.type == ContentType.AUDIO, + 'Audio parameter mismatch!'); + goog.asserts.assert(!video || video.type == ContentType.VIDEO, + 'Video parameter mismatch!'); - return { - id: this.globalId_++, - language: audio ? audio.language : 'und', - primary: (!!audio && audio.primary) || (!!video && video.primary), - audio: audio, - video: video, - bandwidth: bandwidth, - drmInfos: drmInfos, - allowedByApplication: true, - allowedByKeySystem: true, - }; -}; + return { + id: this.globalId_++, + language: audio ? audio.language : 'und', + primary: (!!audio && audio.primary) || (!!video && video.primary), + audio: audio, + video: video, + bandwidth: bandwidth, + drmInfos: drmInfos, + allowedByApplication: true, + allowedByKeySystem: true, + }; + }; /** @@ -916,17 +916,17 @@ shaka.hls.HlsParser.prototype.createVariant_ = */ shaka.hls.HlsParser.prototype.createTextStream_ = async function(tag, playlist) { - goog.asserts.assert(tag.name == 'EXT-X-MEDIA', - 'Should only be called on media tags!'); + goog.asserts.assert(tag.name == 'EXT-X-MEDIA', + 'Should only be called on media tags!'); - const type = shaka.hls.HlsParser.getRequiredAttributeValue_(tag, 'TYPE'); - goog.asserts.assert(type == 'SUBTITLES', - 'Should only be called on tags with TYPE="SUBTITLES"!'); + const type = shaka.hls.HlsParser.getRequiredAttributeValue_(tag, 'TYPE'); + goog.asserts.assert(type == 'SUBTITLES', + 'Should only be called on tags with TYPE="SUBTITLES"!'); - const streamInfo = await this.createStreamInfoFromMediaTag_(tag, []); - goog.asserts.assert(streamInfo, 'Should always have a streamInfo for text'); - return streamInfo.stream; -}; + const streamInfo = await this.createStreamInfoFromMediaTag_(tag, []); + goog.asserts.assert(streamInfo, 'Should always have a streamInfo for text'); + return streamInfo.stream; + }; /** @@ -976,57 +976,57 @@ shaka.hls.HlsParser.prototype.parseClosedCaptions_ = function(tags) { */ shaka.hls.HlsParser.prototype.createStreamInfoFromMediaTag_ = async function(tag, allCodecs) { - goog.asserts.assert(tag.name == 'EXT-X-MEDIA', - 'Should only be called on media tags!'); + goog.asserts.assert(tag.name == 'EXT-X-MEDIA', + 'Should only be called on media tags!'); - const HlsParser = shaka.hls.HlsParser; - const verbatimMediaPlaylistUri = HlsParser.getRequiredAttributeValue_( - tag, 'URI'); + const HlsParser = shaka.hls.HlsParser; + const verbatimMediaPlaylistUri = HlsParser.getRequiredAttributeValue_( + tag, 'URI'); - // Check if the stream has already been created as part of another Variant - // and return it if it has. - if (this.uriToStreamInfosMap_.has(verbatimMediaPlaylistUri)) { - return this.uriToStreamInfosMap_.get(verbatimMediaPlaylistUri); - } + // Check if the stream has already been created as part of another Variant + // and return it if it has. + if (this.uriToStreamInfosMap_.has(verbatimMediaPlaylistUri)) { + return this.uriToStreamInfosMap_.get(verbatimMediaPlaylistUri); + } - let type = HlsParser.getRequiredAttributeValue_(tag, 'TYPE').toLowerCase(); - // Shaka recognizes the content types 'audio', 'video' and 'text'. - // The HLS 'subtitles' type needs to be mapped to 'text'. - const ContentType = shaka.util.ManifestParserUtils.ContentType; - if (type == 'subtitles') { - type = ContentType.TEXT; - } + let type = HlsParser.getRequiredAttributeValue_(tag, 'TYPE').toLowerCase(); + // Shaka recognizes the content types 'audio', 'video' and 'text'. + // The HLS 'subtitles' type needs to be mapped to 'text'. + const ContentType = shaka.util.ManifestParserUtils.ContentType; + if (type == 'subtitles') { + type = ContentType.TEXT; + } - const LanguageUtils = shaka.util.LanguageUtils; - const language = LanguageUtils.normalize(/** @type {string} */( - tag.getAttributeValue('LANGUAGE', 'und'))); - const name = tag.getAttributeValue('NAME'); + const LanguageUtils = shaka.util.LanguageUtils; + const language = LanguageUtils.normalize(/** @type {string} */( + tag.getAttributeValue('LANGUAGE', 'und'))); + const name = tag.getAttributeValue('NAME'); - const defaultAttr = tag.getAttribute('DEFAULT'); - const autoselectAttr = tag.getAttribute('AUTOSELECT'); - // TODO: Should we take into account some of the currently ignored attributes: - // FORCED, INSTREAM-ID, CHARACTERISTICS, CHANNELS? - // Attribute descriptions: https://bit.ly/2lpjOhj - const channelsAttribute = tag.getAttributeValue('CHANNELS'); - const channelsCount = type == 'audio' ? + const defaultAttr = tag.getAttribute('DEFAULT'); + const autoselectAttr = tag.getAttribute('AUTOSELECT'); + // TODO: Should we take into account some of the currently ignored attributes: + // FORCED, INSTREAM-ID, CHARACTERISTICS, CHANNELS? + // Attribute descriptions: https://bit.ly/2lpjOhj + const channelsAttribute = tag.getAttributeValue('CHANNELS'); + const channelsCount = type == 'audio' ? this.getChannelCount_(channelsAttribute) : null; - const primary = !!defaultAttr || !!autoselectAttr; - const streamInfo = await this.createStreamInfo_( - verbatimMediaPlaylistUri, allCodecs, type, language, primary, name, - channelsCount, /* closedCaptions */ null); - if (streamInfo == null) { - return null; - } - // TODO: This check is necessary because of the possibility of multiple - // calls to createStreamInfoFromMediaTag_ before either has resolved. - if (this.uriToStreamInfosMap_.has(verbatimMediaPlaylistUri)) { - return this.uriToStreamInfosMap_.get(verbatimMediaPlaylistUri); - } + const primary = !!defaultAttr || !!autoselectAttr; + const streamInfo = await this.createStreamInfo_( + verbatimMediaPlaylistUri, allCodecs, type, language, primary, name, + channelsCount, /* closedCaptions */ null); + if (streamInfo == null) { + return null; + } + // TODO: This check is necessary because of the possibility of multiple + // calls to createStreamInfoFromMediaTag_ before either has resolved. + if (this.uriToStreamInfosMap_.has(verbatimMediaPlaylistUri)) { + return this.uriToStreamInfosMap_.get(verbatimMediaPlaylistUri); + } - this.mediaTagsToStreamInfosMap_.set(tag.id, streamInfo); - this.uriToStreamInfosMap_.set(verbatimMediaPlaylistUri, streamInfo); - return streamInfo; -}; + this.mediaTagsToStreamInfosMap_.set(tag.id, streamInfo); + this.uriToStreamInfosMap_.set(verbatimMediaPlaylistUri, streamInfo); + return streamInfo; + }; /** @@ -1061,46 +1061,46 @@ shaka.hls.HlsParser.prototype.getChannelCount_ = function(channels) { */ shaka.hls.HlsParser.prototype.createStreamInfoFromVariantTag_ = async function(tag, allCodecs, type) { - goog.asserts.assert(tag.name == 'EXT-X-STREAM-INF', - 'Should only be called on media tags!'); - const ContentType = shaka.util.ManifestParserUtils.ContentType; + goog.asserts.assert(tag.name == 'EXT-X-STREAM-INF', + 'Should only be called on media tags!'); + const ContentType = shaka.util.ManifestParserUtils.ContentType; - const HlsParser = shaka.hls.HlsParser; - const verbatimMediaPlaylistUri = HlsParser.getRequiredAttributeValue_( - tag, 'URI'); + const HlsParser = shaka.hls.HlsParser; + const verbatimMediaPlaylistUri = HlsParser.getRequiredAttributeValue_( + tag, 'URI'); - if (this.uriToStreamInfosMap_.has(verbatimMediaPlaylistUri)) { - return this.uriToStreamInfosMap_.get(verbatimMediaPlaylistUri); - } - // The attribute of closed captions is optional, and the value may be 'NONE'. - const closedCaptionsAttr = tag.getAttributeValue('CLOSED-CAPTIONS'); + if (this.uriToStreamInfosMap_.has(verbatimMediaPlaylistUri)) { + return this.uriToStreamInfosMap_.get(verbatimMediaPlaylistUri); + } + // The attribute of closed captions is optional, and the value may be 'NONE'. + const closedCaptionsAttr = tag.getAttributeValue('CLOSED-CAPTIONS'); - // EXT-X-STREAM-INF tags may have CLOSED-CAPTIONS attributes. - // The value can be either a quoted-string or an enumerated-string with the - // value NONE. If the value is a quoted-string, it MUST match the value of - // the GROUP-ID attribute of an EXT-X-MEDIA tag elsewhere in the Playlist - // whose TYPE attribute is CLOSED-CAPTIONS. - let closedCaptions = null; - if (type == ContentType.VIDEO && closedCaptionsAttr && + // EXT-X-STREAM-INF tags may have CLOSED-CAPTIONS attributes. + // The value can be either a quoted-string or an enumerated-string with the + // value NONE. If the value is a quoted-string, it MUST match the value of + // the GROUP-ID attribute of an EXT-X-MEDIA tag elsewhere in the Playlist + // whose TYPE attribute is CLOSED-CAPTIONS. + let closedCaptions = null; + if (type == ContentType.VIDEO && closedCaptionsAttr && closedCaptionsAttr != 'NONE') { - closedCaptions = this.groupIdToClosedCaptionsMap_.get(closedCaptionsAttr); - } + closedCaptions = this.groupIdToClosedCaptionsMap_.get(closedCaptionsAttr); + } - const streamInfo = await this.createStreamInfo_(verbatimMediaPlaylistUri, - allCodecs, type, /* language */ 'und', /* primary */ false, - /* name */ null, /* channelcount */ null, closedCaptions); - if (streamInfo == null) { - return null; - } - // TODO: This check is necessary because of the possibility of multiple - // calls to createStreamInfoFromVariantTag_ before either has resolved. - if (this.uriToStreamInfosMap_.has(verbatimMediaPlaylistUri)) { - return this.uriToStreamInfosMap_.get(verbatimMediaPlaylistUri); - } + const streamInfo = await this.createStreamInfo_(verbatimMediaPlaylistUri, + allCodecs, type, /* language */ 'und', /* primary */ false, + /* name */ null, /* channelcount */ null, closedCaptions); + if (streamInfo == null) { + return null; + } + // TODO: This check is necessary because of the possibility of multiple + // calls to createStreamInfoFromVariantTag_ before either has resolved. + if (this.uriToStreamInfosMap_.has(verbatimMediaPlaylistUri)) { + return this.uriToStreamInfosMap_.get(verbatimMediaPlaylistUri); + } - this.uriToStreamInfosMap_.set(verbatimMediaPlaylistUri, streamInfo); - return streamInfo; -}; + this.uriToStreamInfosMap_.set(verbatimMediaPlaylistUri, streamInfo); + return streamInfo; + }; /** @@ -1149,7 +1149,7 @@ shaka.hls.HlsParser.prototype.createStreamInfo_ = async function( const drmTags = []; playlist.segments.forEach((segment) => { const segmentKeyTags = Utils.filterTagsByName(segment.tags, - 'EXT-X-KEY'); + 'EXT-X-KEY'); drmTags.push.apply(drmTags, segmentKeyTags); }); @@ -1200,7 +1200,7 @@ shaka.hls.HlsParser.prototype.createStreamInfo_ = async function( goog.asserts.assert(playlist.segments != null, - 'Media playlist should have segments!'); + 'Media playlist should have segments!'); this.determinePresentationType_(playlist); @@ -1211,7 +1211,7 @@ shaka.hls.HlsParser.prototype.createStreamInfo_ = async function( const mimeType = mimeTypeArg; const mediaSequenceTag = Utils.getFirstTagWithName(playlist.tags, - 'EXT-X-MEDIA-SEQUENCE'); + 'EXT-X-MEDIA-SEQUENCE'); const startPosition = mediaSequenceTag ? Number(mediaSequenceTag.value) : 0; @@ -1282,7 +1282,7 @@ shaka.hls.HlsParser.prototype.determinePresentationType_ = function(playlist) { const Utils = shaka.hls.Utils; const PresentationType = shaka.hls.HlsParser.PresentationType_; const presentationTypeTag = Utils.getFirstTagWithName(playlist.tags, - 'EXT-X-PLAYLIST-TYPE'); + 'EXT-X-PLAYLIST-TYPE'); const endListTag = Utils.getFirstTagWithName(playlist.tags, 'EXT-X-ENDLIST'); const isVod = (presentationTypeTag && presentationTypeTag.value == 'VOD') || @@ -1302,7 +1302,7 @@ shaka.hls.HlsParser.prototype.determinePresentationType_ = function(playlist) { } const targetDurationTag = this.getRequiredTag_(playlist.tags, - 'EXT-X-TARGETDURATION'); + 'EXT-X-TARGETDURATION'); const targetDuration = Number(targetDurationTag.value); // According to the HLS spec, updates should not happen more often than @@ -1328,37 +1328,37 @@ shaka.hls.HlsParser.prototype.determinePresentationType_ = function(playlist) { */ shaka.hls.HlsParser.prototype.createPresentationTimeline_ = function(lastTimestamp) { - if (this.isLive_()) { - // The live edge will be calculated from segments, so we don't need to set - // a presentation start time. We will assert later that this is working as - // expected. + if (this.isLive_()) { + // The live edge will be calculated from segments, so we don't need to set + // a presentation start time. We will assert later that this is working as + // expected. - // The HLS spec (RFC 8216) states in 6.3.3: - // - // "The client SHALL choose which Media Segment to play first ... the - // client SHOULD NOT choose a segment that starts less than three target - // durations from the end of the Playlist file. Doing so can trigger - // playback stalls." - // - // We accomplish this in our DASH-y model by setting a presentation delay - // of 3 segments. This will be the "live edge" of the presentation. - this.presentationTimeline_ = new shaka.media.PresentationTimeline( + // The HLS spec (RFC 8216) states in 6.3.3: + // + // "The client SHALL choose which Media Segment to play first ... the + // client SHOULD NOT choose a segment that starts less than three target + // durations from the end of the Playlist file. Doing so can trigger + // playback stalls." + // + // We accomplish this in our DASH-y model by setting a presentation delay + // of 3 segments. This will be the "live edge" of the presentation. + this.presentationTimeline_ = new shaka.media.PresentationTimeline( /* presentationStartTime */ 0, /* delay */ this.maxTargetDuration_ * 3); - this.presentationTimeline_.setStatic(false); - } else { - this.presentationTimeline_ = new shaka.media.PresentationTimeline( + this.presentationTimeline_.setStatic(false); + } else { + this.presentationTimeline_ = new shaka.media.PresentationTimeline( /* presentationStartTime */ null, /* delay */ 0); - this.presentationTimeline_.setStatic(true); - } + this.presentationTimeline_.setStatic(true); + } - this.notifySegments_(); + this.notifySegments_(); - // This asserts that the live edge is being calculated from segment times. - // For VOD and event streams, this check should still pass. - goog.asserts.assert( - !this.presentationTimeline_.usingPresentationStartTime(), - 'We should not be using the presentation start time in HLS!'); -}; + // This asserts that the live edge is being calculated from segment times. + // For VOD and event streams, this check should still pass. + goog.asserts.assert( + !this.presentationTimeline_.usingPresentationStartTime(), + 'We should not be using the presentation start time in HLS!'); + }; /** @@ -1420,43 +1420,43 @@ shaka.hls.HlsParser.prototype.createInitSegmentReference_ = function(playlist) { */ shaka.hls.HlsParser.prototype.createSegmentReference_ = function(playlist, previousReference, hlsSegment, position, startTime) { - const Utils = shaka.hls.Utils; - const tags = hlsSegment.tags; - const absoluteSegmentUri = hlsSegment.absoluteUri; + const Utils = shaka.hls.Utils; + const tags = hlsSegment.tags; + const absoluteSegmentUri = hlsSegment.absoluteUri; - const extinfTag = this.getRequiredTag_(tags, 'EXTINF'); - // The EXTINF tag format is '#EXTINF:,[]'. - // We're interested in the duration part. - const extinfValues = extinfTag.value.split(','); - const duration = Number(extinfValues[0]); - const endTime = startTime + duration; + const extinfTag = this.getRequiredTag_(tags, 'EXTINF'); + // The EXTINF tag format is '#EXTINF:<duration>,[<title>]'. + // We're interested in the duration part. + const extinfValues = extinfTag.value.split(','); + const duration = Number(extinfValues[0]); + const endTime = startTime + duration; - let startByte = 0; - let endByte = null; - const byterange = Utils.getFirstTagWithName(tags, 'EXT-X-BYTERANGE'); + let startByte = 0; + let endByte = null; + const byterange = Utils.getFirstTagWithName(tags, 'EXT-X-BYTERANGE'); - // If BYTERANGE is not specified, the segment consists of the entire resource. - if (byterange) { - const blocks = byterange.value.split('@'); - const byteLength = Number(blocks[0]); - if (blocks[1]) { - startByte = Number(blocks[1]); - } else { - goog.asserts.assert(previousReference, - 'Cannot refer back to previous HLS segment!'); - startByte = previousReference.endByte + 1; - } - endByte = startByte + byteLength - 1; - } + // If BYTERANGE is not specified, the segment consists of the entire resource. + if (byterange) { + const blocks = byterange.value.split('@'); + const byteLength = Number(blocks[0]); + if (blocks[1]) { + startByte = Number(blocks[1]); + } else { + goog.asserts.assert(previousReference, + 'Cannot refer back to previous HLS segment!'); + startByte = previousReference.endByte + 1; + } + endByte = startByte + byteLength - 1; + } - return new shaka.media.SegmentReference( - position, - startTime, - endTime, - () => [absoluteSegmentUri], - startByte, - endByte); -}; + return new shaka.media.SegmentReference( + position, + startTime, + endTime, + () => [absoluteSegmentUri], + startByte, + endByte); + }; /** @private */ @@ -1506,9 +1506,9 @@ shaka.hls.HlsParser.prototype.createSegments_ = async function( const initSegmentRef = this.createInitSegmentReference_(playlist); const firstStartTime = await this.getStartTime_(verbatimMediaPlaylistUri, - initSegmentRef, firstSegmentRef, mimeType, codecs); + initSegmentRef, firstSegmentRef, mimeType, codecs); shaka.log.debug('First segment', firstSegmentUri.split('/').pop(), - 'starts at', firstStartTime); + 'starts at', firstStartTime); for (let i = 0; i < hlsSegments.length; ++i) { const hlsSegment = hlsSegments[i]; const previousReference = references[references.length - 1]; @@ -1589,7 +1589,7 @@ shaka.hls.HlsParser.prototype.fetchPartialSegment_ = async function(reference) { 'Falling back to a full segment request, ' + 'which is expensive! Your server should ' + 'support Range requests and CORS preflights.', - partialRequest.uris[0]); + partialRequest.uris[0]); const response = await this.makeNetworkRequest_( fullRequest, RequestType.SEGMENT); @@ -1707,60 +1707,60 @@ shaka.hls.HlsParser.prototype.getStartTime_ = async function( */ shaka.hls.HlsParser.prototype.getStartTimeFromMp4Segment_ = function(mediaData, initData) { - const Mp4Parser = shaka.util.Mp4Parser; + const Mp4Parser = shaka.util.Mp4Parser; - let timescale = 0; - new Mp4Parser() - .box('moov', Mp4Parser.children) - .box('trak', Mp4Parser.children) - .box('mdia', Mp4Parser.children) - .fullBox('mdhd', (box) => { - goog.asserts.assert( - box.version == 0 || box.version == 1, - 'MDHD version can only be 0 or 1'); + let timescale = 0; + new Mp4Parser() + .box('moov', Mp4Parser.children) + .box('trak', Mp4Parser.children) + .box('mdia', Mp4Parser.children) + .fullBox('mdhd', (box) => { + goog.asserts.assert( + box.version == 0 || box.version == 1, + 'MDHD version can only be 0 or 1'); - // Skip "creation_time" and "modification_time". - // They are 4 bytes each if the mdhd box is version 0, 8 bytes each if - // it is version 1. - box.reader.skip(box.version == 0 ? 8 : 16); + // Skip "creation_time" and "modification_time". + // They are 4 bytes each if the mdhd box is version 0, 8 bytes each if + // it is version 1. + box.reader.skip(box.version == 0 ? 8 : 16); - timescale = box.reader.readUint32(); - box.parser.stop(); - }).parse(initData, true /* partialOkay */); + timescale = box.reader.readUint32(); + box.parser.stop(); + }).parse(initData, true /* partialOkay */); - if (!timescale) { - shaka.log.error('Unable to find timescale in init segment!'); - throw new shaka.util.Error( - shaka.util.Error.Severity.CRITICAL, - shaka.util.Error.Category.MANIFEST, - shaka.util.Error.Code.HLS_COULD_NOT_PARSE_SEGMENT_START_TIME); - } + if (!timescale) { + shaka.log.error('Unable to find timescale in init segment!'); + throw new shaka.util.Error( + shaka.util.Error.Severity.CRITICAL, + shaka.util.Error.Category.MANIFEST, + shaka.util.Error.Code.HLS_COULD_NOT_PARSE_SEGMENT_START_TIME); + } - let startTime = 0; - let parsedMedia = false; - new Mp4Parser() - .box('moof', Mp4Parser.children) - .box('traf', Mp4Parser.children) - .fullBox('tfdt', (box) => { - goog.asserts.assert( - box.version == 0 || box.version == 1, - 'TFDT version can only be 0 or 1'); - const baseTime = (box.version == 0) ? + let startTime = 0; + let parsedMedia = false; + new Mp4Parser() + .box('moof', Mp4Parser.children) + .box('traf', Mp4Parser.children) + .fullBox('tfdt', (box) => { + goog.asserts.assert( + box.version == 0 || box.version == 1, + 'TFDT version can only be 0 or 1'); + const baseTime = (box.version == 0) ? box.reader.readUint32() : box.reader.readUint64(); - startTime = baseTime / timescale; - parsedMedia = true; - box.parser.stop(); - }).parse(mediaData, true /* partialOkay */); + startTime = baseTime / timescale; + parsedMedia = true; + box.parser.stop(); + }).parse(mediaData, true /* partialOkay */); - if (!parsedMedia) { - throw new shaka.util.Error( - shaka.util.Error.Severity.CRITICAL, - shaka.util.Error.Category.MANIFEST, - shaka.util.Error.Code.HLS_COULD_NOT_PARSE_SEGMENT_START_TIME); - } - return startTime; -}; + if (!parsedMedia) { + throw new shaka.util.Error( + shaka.util.Error.Severity.CRITICAL, + shaka.util.Error.Category.MANIFEST, + shaka.util.Error.Code.HLS_COULD_NOT_PARSE_SEGMENT_START_TIME); + } + return startTime; + }; /** @@ -1893,17 +1893,17 @@ shaka.hls.HlsParser.prototype.getStartTimeFromTsSegment_ = function(data) { */ shaka.hls.HlsParser.prototype.getStartTimeFromTextSegment_ = function(mimeType, codecs, data) { - const fullMimeType = shaka.util.MimeUtils.getFullType(mimeType, codecs); - if (!shaka.text.TextEngine.isTypeSupported(fullMimeType)) { - // We won't be able to parse this, but it will be filtered out anyway. - // So we don't have to care about the start time. - return 0; - } + const fullMimeType = shaka.util.MimeUtils.getFullType(mimeType, codecs); + if (!shaka.text.TextEngine.isTypeSupported(fullMimeType)) { + // We won't be able to parse this, but it will be filtered out anyway. + // So we don't have to care about the start time. + return 0; + } - const textEngine = new shaka.text.TextEngine(/* displayer */ null); - textEngine.initParser(fullMimeType); - return textEngine.getStartTime(data); -}; + const textEngine = new shaka.text.TextEngine(/* displayer */ null); + textEngine.initParser(fullMimeType); + return textEngine.getStartTime(data); + }; /** @@ -2008,58 +2008,58 @@ shaka.hls.HlsParser.prototype.guessCodecs_ = function(contentType, codecs) { */ shaka.hls.HlsParser.prototype.guessMimeType_ = async function(contentType, codecs, playlist) { - const ContentType = shaka.util.ManifestParserUtils.ContentType; - const HlsParser = shaka.hls.HlsParser; - const RequestType = shaka.net.NetworkingEngine.RequestType; + const ContentType = shaka.util.ManifestParserUtils.ContentType; + const HlsParser = shaka.hls.HlsParser; + const RequestType = shaka.net.NetworkingEngine.RequestType; - goog.asserts.assert(playlist.segments.length, - 'Playlist should have segments!'); - const firstSegmentUri = playlist.segments[0].absoluteUri; + goog.asserts.assert(playlist.segments.length, + 'Playlist should have segments!'); + const firstSegmentUri = playlist.segments[0].absoluteUri; - const parsedUri = new goog.Uri(firstSegmentUri); - const extension = parsedUri.getPath().split('.').pop(); - const map = HlsParser.EXTENSION_MAP_BY_CONTENT_TYPE_[contentType]; + const parsedUri = new goog.Uri(firstSegmentUri); + const extension = parsedUri.getPath().split('.').pop(); + const map = HlsParser.EXTENSION_MAP_BY_CONTENT_TYPE_[contentType]; - const mimeType = map[extension]; - if (mimeType) { - return mimeType; - } + const mimeType = map[extension]; + if (mimeType) { + return mimeType; + } - if (contentType == ContentType.TEXT) { - // The extension map didn't work. - if (!codecs || codecs == 'vtt') { - // If codecs is 'vtt', it's WebVTT. - // If there was no codecs string, assume HLS text streams are WebVTT. - return 'text/vtt'; - } else { - // Otherwise, assume MP4-embedded text, since text-based formats tend not - // to have a codecs string at all. - return 'application/mp4'; - } - } + if (contentType == ContentType.TEXT) { + // The extension map didn't work. + if (!codecs || codecs == 'vtt') { + // If codecs is 'vtt', it's WebVTT. + // If there was no codecs string, assume HLS text streams are WebVTT. + return 'text/vtt'; + } else { + // Otherwise, assume MP4-embedded text, since text-based formats tend not + // to have a codecs string at all. + return 'application/mp4'; + } + } - // If unable to guess mime type, request a segment and try getting it - // from the response. - const headRequest = shaka.net.NetworkingEngine.makeRequest( - [firstSegmentUri], this.config_.retryParameters); - headRequest.method = 'HEAD'; + // If unable to guess mime type, request a segment and try getting it + // from the response. + const headRequest = shaka.net.NetworkingEngine.makeRequest( + [firstSegmentUri], this.config_.retryParameters); + headRequest.method = 'HEAD'; - const response = await this.makeNetworkRequest_( - headRequest, RequestType.SEGMENT); + const response = await this.makeNetworkRequest_( + headRequest, RequestType.SEGMENT); - const contentMimeType = response.headers['content-type']; + const contentMimeType = response.headers['content-type']; - if (!contentMimeType) { - throw new shaka.util.Error( - shaka.util.Error.Severity.CRITICAL, - shaka.util.Error.Category.MANIFEST, - shaka.util.Error.Code.HLS_COULD_NOT_GUESS_MIME_TYPE, - extension); - } + if (!contentMimeType) { + throw new shaka.util.Error( + shaka.util.Error.Severity.CRITICAL, + shaka.util.Error.Category.MANIFEST, + shaka.util.Error.Code.HLS_COULD_NOT_GUESS_MIME_TYPE, + extension); + } - // Split the MIME type in case the server sent additional parameters. - return contentMimeType.split(';')[0]; -}; + // Split the MIME type in case the server sent additional parameters. + return contentMimeType.split(';')[0]; + }; /** @@ -2119,12 +2119,12 @@ shaka.hls.HlsParser.prototype.getRequiredTag_ = function(tags, tagName) { */ shaka.hls.HlsParser.prototype.addVideoAttributes_ = function(stream, width, height, frameRate) { - if (stream) { - stream.width = Number(width) || undefined; - stream.height = Number(height) || undefined; - stream.frameRate = Number(frameRate) || undefined; - } -}; + if (stream) { + stream.width = Number(width) || undefined; + stream.height = Number(height) || undefined; + stream.frameRate = Number(frameRate) || undefined; + } + }; /** @@ -2272,7 +2272,7 @@ shaka.hls.HlsParser.widevineDrmParser_ = function(drmTag) { const VALID_METHODS = ['SAMPLE-AES', 'SAMPLE-AES-CTR', 'SAMPLE-AES-CENC']; if (!VALID_METHODS.includes(method)) { shaka.log.error('Widevine in HLS is only supported with [', - VALID_METHODS.join(', '), '], not', method); + VALID_METHODS.join(', '), '], not', method); return null; } @@ -2324,7 +2324,7 @@ shaka.hls.HlsParser.prototype.onUpdate_ = async function() { this.updatePlaylistTimer_.tickAfter(/* seconds= */ delay); } catch (error) { goog.asserts.assert(error instanceof shaka.util.Error, - 'Should only receive a Shaka error'); + 'Should only receive a Shaka error'); // We will retry updating, so override the severity of the error. error.severity = shaka.util.Error.Severity.RECOVERABLE; diff --git a/lib/hls/manifest_text_parser.js b/lib/hls/manifest_text_parser.js index 2dc8526e2..18ab97ee0 100644 --- a/lib/hls/manifest_text_parser.js +++ b/lib/hls/manifest_text_parser.js @@ -48,83 +48,83 @@ shaka.hls.ManifestTextParser = function() { */ shaka.hls.ManifestTextParser.prototype.parsePlaylist = function(data, absolutePlaylistUri) { - const MEDIA_PLAYLIST_TAGS = shaka.hls.ManifestTextParser.MEDIA_PLAYLIST_TAGS; - const SEGMENT_TAGS = shaka.hls.ManifestTextParser.SEGMENT_TAGS; + const MEDIA_PLAYLIST_TAGS = shaka.hls.ManifestTextParser.MEDIA_PLAYLIST_TAGS; + const SEGMENT_TAGS = shaka.hls.ManifestTextParser.SEGMENT_TAGS; - // Get the input as a string. Normalize newlines to \n. - let str = shaka.util.StringUtils.fromUTF8(data); - str = str.replace(/\r\n|\r(?=[^\n]|$)/gm, '\n').trim(); + // Get the input as a string. Normalize newlines to \n. + let str = shaka.util.StringUtils.fromUTF8(data); + str = str.replace(/\r\n|\r(?=[^\n]|$)/gm, '\n').trim(); - const lines = str.split(/\n+/m); + const lines = str.split(/\n+/m); - if (!/^#EXTM3U($|[ \t\n])/m.test(lines[0])) { - throw new shaka.util.Error( - shaka.util.Error.Severity.CRITICAL, - shaka.util.Error.Category.MANIFEST, - shaka.util.Error.Code.HLS_PLAYLIST_HEADER_MISSING); - } - - /** shaka.hls.PlaylistType */ - let playlistType = shaka.hls.PlaylistType.MASTER; - - // First, look for media playlist tags, so that we know what the playlist - // type really is before we start parsing. - for (let i = 1; i < lines.length; i++) { - // Ignore comments. - if (!shaka.hls.Utils.isComment(lines[i])) { - const tag = this.parseTag_(lines[i]); - // These tags won't actually be used, so don't increment the global id. - this.globalId_ -= 1; - - if (MEDIA_PLAYLIST_TAGS.includes(tag.name)) { - playlistType = shaka.hls.PlaylistType.MEDIA; - break; - } else if (tag.name == 'EXT-X-STREAM-INF') { - i += 1; - } - } - } - - /** {Array.<shaka.hls.Tag>} */ - const tags = []; - for (let i = 1; i < lines.length;) { - // Skip comments - if (shaka.hls.Utils.isComment(lines[i])) { - i += 1; - continue; - } - - const tag = this.parseTag_(lines[i]); - if (SEGMENT_TAGS.includes(tag.name)) { - if (playlistType != shaka.hls.PlaylistType.MEDIA) { - // Only media playlists should contain segment tags + if (!/^#EXTM3U($|[ \t\n])/m.test(lines[0])) { throw new shaka.util.Error( shaka.util.Error.Severity.CRITICAL, shaka.util.Error.Category.MANIFEST, - shaka.util.Error.Code.HLS_INVALID_PLAYLIST_HIERARCHY); + shaka.util.Error.Code.HLS_PLAYLIST_HEADER_MISSING); } - const segmentsData = lines.splice(i, lines.length - i); - const segments = this.parseSegments_( - absolutePlaylistUri, segmentsData, tags); - return new shaka.hls.Playlist( - absolutePlaylistUri, playlistType, tags, segments); - } + /** shaka.hls.PlaylistType */ + let playlistType = shaka.hls.PlaylistType.MASTER; - tags.push(tag); - i += 1; + // First, look for media playlist tags, so that we know what the playlist + // type really is before we start parsing. + for (let i = 1; i < lines.length; i++) { + // Ignore comments. + if (!shaka.hls.Utils.isComment(lines[i])) { + const tag = this.parseTag_(lines[i]); + // These tags won't actually be used, so don't increment the global id. + this.globalId_ -= 1; - // An EXT-X-STREAM-INF tag is followed by a URI of a media playlist. - // Add the URI to the tag object. - if (tag.name == 'EXT-X-STREAM-INF') { - const tagUri = new shaka.hls.Attribute('URI', lines[i]); - tag.addAttribute(tagUri); - i += 1; - } - } + if (MEDIA_PLAYLIST_TAGS.includes(tag.name)) { + playlistType = shaka.hls.PlaylistType.MEDIA; + break; + } else if (tag.name == 'EXT-X-STREAM-INF') { + i += 1; + } + } + } - return new shaka.hls.Playlist(absolutePlaylistUri, playlistType, tags); -}; + /** {Array.<shaka.hls.Tag>} */ + const tags = []; + for (let i = 1; i < lines.length;) { + // Skip comments + if (shaka.hls.Utils.isComment(lines[i])) { + i += 1; + continue; + } + + const tag = this.parseTag_(lines[i]); + if (SEGMENT_TAGS.includes(tag.name)) { + if (playlistType != shaka.hls.PlaylistType.MEDIA) { + // Only media playlists should contain segment tags + throw new shaka.util.Error( + shaka.util.Error.Severity.CRITICAL, + shaka.util.Error.Category.MANIFEST, + shaka.util.Error.Code.HLS_INVALID_PLAYLIST_HIERARCHY); + } + + const segmentsData = lines.splice(i, lines.length - i); + const segments = this.parseSegments_( + absolutePlaylistUri, segmentsData, tags); + return new shaka.hls.Playlist( + absolutePlaylistUri, playlistType, tags, segments); + } + + tags.push(tag); + i += 1; + + // An EXT-X-STREAM-INF tag is followed by a URI of a media playlist. + // Add the URI to the tag object. + if (tag.name == 'EXT-X-STREAM-INF') { + const tagUri = new shaka.hls.Attribute('URI', lines[i]); + tag.addAttribute(tagUri); + i += 1; + } + } + + return new shaka.hls.Playlist(absolutePlaylistUri, playlistType, tags); + }; /** @@ -139,33 +139,33 @@ shaka.hls.ManifestTextParser.prototype.parsePlaylist = */ shaka.hls.ManifestTextParser.prototype.parseSegments_ = function(absoluteMediaPlaylistUri, lines, playlistTags) { - /** @type {!Array.<shaka.hls.Segment>} */ - const segments = []; - /** @type {!Array.<shaka.hls.Tag>} */ - let segmentTags = []; - lines.forEach((line) => { - if (/^(#EXT)/.test(line)) { - const tag = this.parseTag_(line); - if (shaka.hls.ManifestTextParser.MEDIA_PLAYLIST_TAGS.includes(tag.name)) { - playlistTags.push(tag); - } else { - segmentTags.push(tag); - } - } else if (shaka.hls.Utils.isComment(line)) { - // Skip comments. - } else { - const verbatimSegmentUri = line.trim(); - const absoluteSegmentUri = shaka.hls.Utils.constructAbsoluteUri( - absoluteMediaPlaylistUri, verbatimSegmentUri); + /** @type {!Array.<shaka.hls.Segment>} */ + const segments = []; + /** @type {!Array.<shaka.hls.Tag>} */ + let segmentTags = []; + lines.forEach((line) => { + if (/^(#EXT)/.test(line)) { + const tag = this.parseTag_(line); + if (shaka.hls.ManifestTextParser.MEDIA_PLAYLIST_TAGS.includes(tag.name)) { + playlistTags.push(tag); + } else { + segmentTags.push(tag); + } + } else if (shaka.hls.Utils.isComment(line)) { + // Skip comments. + } else { + const verbatimSegmentUri = line.trim(); + const absoluteSegmentUri = shaka.hls.Utils.constructAbsoluteUri( + absoluteMediaPlaylistUri, verbatimSegmentUri); - // The URI appears after all of the tags describing the segment. - const segment = new shaka.hls.Segment(absoluteSegmentUri, segmentTags); - segments.push(segment); - segmentTags = []; - } - }); - return segments; -}; + // The URI appears after all of the tags describing the segment. + const segment = new shaka.hls.Segment(absoluteSegmentUri, segmentTags); + segments.push(segment); + segmentTags = []; + } + }); + return segments; + }; /** diff --git a/lib/media/closed_caption_parser.js b/lib/media/closed_caption_parser.js index f1d92437f..d92cfb2e1 100644 --- a/lib/media/closed_caption_parser.js +++ b/lib/media/closed_caption_parser.js @@ -90,7 +90,7 @@ shaka.media.MuxJSClosedCaptionParser = class { parseFrom(data, onCaptions) { const segmentBytes = new Uint8Array(data); const dashParsed = this.muxCaptionParser_.parse( - segmentBytes, this.videoTrackIds_, this.timescales_); + segmentBytes, this.videoTrackIds_, this.timescales_); if (dashParsed && dashParsed.captions) { onCaptions(dashParsed.captions); } diff --git a/lib/media/drm_engine.js b/lib/media/drm_engine.js index e07c3800b..ca0f06d44 100644 --- a/lib/media/drm_engine.js +++ b/lib/media/drm_engine.js @@ -201,7 +201,7 @@ shaka.media.DrmEngine.prototype.destroy = async function() { // If we have started destroying ourselves, wait for the common "I am finished // being destroyed" promise to be resolved. if (this.isDestroying_) { - await this.finishedDestroyingPromise_; + await this.finishedDestroyingPromise_; } else { this.isDestroying_ = true; await this.destroyNow_(); @@ -501,7 +501,7 @@ shaka.media.DrmEngine.prototype.attach = function(video) { // Explicit init data for any one stream or an offline session is // sufficient to suppress 'encrypted' events for all streams. const cb = (e) => - this.newInitData(e.initDataType, new Uint8Array(e.initData)); + this.newInitData(e.initDataType, new Uint8Array(e.initData)); this.eventManager_.listen(this.video_, 'encrypted', cb); } }).catch((error) => { @@ -520,7 +520,7 @@ shaka.media.DrmEngine.prototype.attach = function(video) { */ shaka.media.DrmEngine.prototype.setServerCertificate = async function() { goog.asserts.assert(this.initialized_, - 'Must call init() before setServerCertificate'); + 'Must call init() before setServerCertificate'); if (this.mediaKeys_ && this.currentDrmInfo_ && @@ -535,10 +535,10 @@ shaka.media.DrmEngine.prototype.setServerCertificate = async function() { } } catch (exception) { throw new shaka.util.Error( - shaka.util.Error.Severity.CRITICAL, - shaka.util.Error.Category.DRM, - shaka.util.Error.Code.INVALID_SERVER_CERTIFICATE, - exception.message); + shaka.util.Error.Severity.CRITICAL, + shaka.util.Error.Category.DRM, + shaka.util.Error.Code.INVALID_SERVER_CERTIFICATE, + exception.message); } } }; @@ -593,7 +593,7 @@ shaka.media.DrmEngine.prototype.createOrLoad = function() { const initDatas = this.currentDrmInfo_ ? this.currentDrmInfo_.initData : []; initDatas.forEach((initDataOverride) => { return this.createTemporarySession_(initDataOverride.initDataType, - initDataOverride.initData); + initDataOverride.initData); }); // Load each session. @@ -918,7 +918,7 @@ shaka.media.DrmEngine.prototype.queryMediaKeys_ = function(configsByKeySystem) { } goog.asserts.assert(this.supportedTypes_.size, - 'We should get at least one supported MIME type'); + 'We should get at least one supported MIME type'); this.currentDrmInfo_ = shaka.media.DrmEngine.createDrmInfoFor_( mediaKeySystemAccess.keySystem, @@ -938,7 +938,7 @@ shaka.media.DrmEngine.prototype.queryMediaKeys_ = function(configsByKeySystem) { return; } shaka.log.info('Created MediaKeys object for key system', - this.currentDrmInfo_.keySystem); + this.currentDrmInfo_.keySystem); this.mediaKeys_ = mediaKeys; this.initialized_ = true; @@ -1044,7 +1044,7 @@ shaka.media.DrmEngine.prototype.loadOfflineSession_ = function(sessionId) { this.eventManager_.listen(session, 'message', /** @type {shaka.util.EventManager.ListenerType} */( - this.onSessionMessage_.bind(this))); + this.onSessionMessage_.bind(this))); this.eventManager_.listen(session, 'keystatuseschange', this.onKeyStatusesChange_.bind(this)); @@ -1103,61 +1103,61 @@ shaka.media.DrmEngine.prototype.loadOfflineSession_ = function(sessionId) { */ shaka.media.DrmEngine.prototype.createTemporarySession_ = function(initDataType, initData) { - let session; - try { - if (this.usePersistentLicenses_) { - shaka.log.v1('Creating new persistent session'); - session = this.mediaKeys_.createSession('persistent-license'); - } else { - shaka.log.v1('Creating new temporary session'); - session = this.mediaKeys_.createSession(); - } - } catch (exception) { - this.onError_(new shaka.util.Error( - shaka.util.Error.Severity.CRITICAL, - shaka.util.Error.Category.DRM, - shaka.util.Error.Code.FAILED_TO_CREATE_SESSION, - exception.message)); - return; - } - - this.eventManager_.listen(session, 'message', - /** @type {shaka.util.EventManager.ListenerType} */( - this.onSessionMessage_.bind(this))); - this.eventManager_.listen(session, 'keystatuseschange', - this.onKeyStatusesChange_.bind(this)); - - const metadata = { - initData: initData, - loaded: false, - oldExpiration: Infinity, - updatePromise: null, - }; - this.activeSessions_.set(session, metadata); - - session.generateRequest(initDataType, initData.buffer).catch((error) => { - if (this.isDestroying_) { - return; - } - - this.activeSessions_.delete(session); - - let extended; - if (error.errorCode && error.errorCode.systemCode) { - extended = error.errorCode.systemCode; - if (extended < 0) { - extended += Math.pow(2, 32); + let session; + try { + if (this.usePersistentLicenses_) { + shaka.log.v1('Creating new persistent session'); + session = this.mediaKeys_.createSession('persistent-license'); + } else { + shaka.log.v1('Creating new temporary session'); + session = this.mediaKeys_.createSession(); + } + } catch (exception) { + this.onError_(new shaka.util.Error( + shaka.util.Error.Severity.CRITICAL, + shaka.util.Error.Category.DRM, + shaka.util.Error.Code.FAILED_TO_CREATE_SESSION, + exception.message)); + return; } - extended = '0x' + extended.toString(16); - } - this.onError_(new shaka.util.Error( - shaka.util.Error.Severity.CRITICAL, - shaka.util.Error.Category.DRM, - shaka.util.Error.Code.FAILED_TO_GENERATE_LICENSE_REQUEST, - error.message, error, extended)); - }); -}; + this.eventManager_.listen(session, 'message', + /** @type {shaka.util.EventManager.ListenerType} */( + this.onSessionMessage_.bind(this))); + this.eventManager_.listen(session, 'keystatuseschange', + this.onKeyStatusesChange_.bind(this)); + + const metadata = { + initData: initData, + loaded: false, + oldExpiration: Infinity, + updatePromise: null, + }; + this.activeSessions_.set(session, metadata); + + session.generateRequest(initDataType, initData.buffer).catch((error) => { + if (this.isDestroying_) { + return; + } + + this.activeSessions_.delete(session); + + let extended; + if (error.errorCode && error.errorCode.systemCode) { + extended = error.errorCode.systemCode; + if (extended < 0) { + extended += Math.pow(2, 32); + } + extended = '0x' + extended.toString(16); + } + + this.onError_(new shaka.util.Error( + shaka.util.Error.Severity.CRITICAL, + shaka.util.Error.Category.DRM, + shaka.util.Error.Code.FAILED_TO_GENERATE_LICENSE_REQUEST, + error.message, error, extended)); + }); + }; /** @@ -1259,7 +1259,7 @@ shaka.media.DrmEngine.prototype.sendLicenseRequest_ = function(event) { // Request failed! goog.asserts.assert(error instanceof shaka.util.Error, - 'Wrong NetworkingEngine error type!'); + 'Wrong NetworkingEngine error type!'); const shakaErr = new shaka.util.Error( shaka.util.Error.Severity.CRITICAL, shaka.util.Error.Category.DRM, @@ -1344,7 +1344,7 @@ shaka.media.DrmEngine.prototype.unpackPlayReadyRequest_ = function(request) { const challenge = dom.querySelector('Challenge'); goog.asserts.assert(challenge, 'Malformed PlayReady challenge!'); goog.asserts.assert(challenge.getAttribute('encoding') == 'base64encoded', - 'Unexpected PlayReady challenge encoding!'); + 'Unexpected PlayReady challenge encoding!'); request.body = shaka.util.Uint8ArrayUtils.fromBase64(challenge.textContent).buffer; }; @@ -1579,7 +1579,7 @@ shaka.media.DrmEngine.isBrowserSupported = function() { */ shaka.media.DrmEngine.probeSupport = function() { goog.asserts.assert(shaka.media.DrmEngine.isBrowserSupported(), - 'Must have basic EME support'); + 'Must have basic EME support'); const testKeySystems = [ 'org.w3.clearkey', @@ -1905,56 +1905,56 @@ shaka.media.DrmEngine.createDrmInfoFor_ = function(keySystem, config) { */ shaka.media.DrmEngine.processDrmInfos_ = function(drmInfos, licenseServers, serverCerts, initDatas, keyIds) { - /** @type {function(shaka.extern.InitDataOverride, + /** @type {function(shaka.extern.InitDataOverride, * shaka.extern.InitDataOverride):boolean} */ - const initDataOverrideEqual = (a, b) => { - if (a.keyId && a.keyId == b.keyId) { - // Two initDatas with the same keyId are considered to be the same, - // unless that "same keyId" is null. - return true; - } - return a.initDataType == b.initDataType && + const initDataOverrideEqual = (a, b) => { + if (a.keyId && a.keyId == b.keyId) { + // Two initDatas with the same keyId are considered to be the same, + // unless that "same keyId" is null. + return true; + } + return a.initDataType == b.initDataType && shaka.util.Uint8ArrayUtils.equal(a.initData, b.initData); - }; + }; - drmInfos.forEach((drmInfo) => { - // Aliases: - const Uint8ArrayUtils = shaka.util.Uint8ArrayUtils; + drmInfos.forEach((drmInfo) => { + // Aliases: + const Uint8ArrayUtils = shaka.util.Uint8ArrayUtils; - // Build an array of unique license servers. - if (!licenseServers.includes(drmInfo.licenseServerUri)) { - licenseServers.push(drmInfo.licenseServerUri); - } + // Build an array of unique license servers. + if (!licenseServers.includes(drmInfo.licenseServerUri)) { + licenseServers.push(drmInfo.licenseServerUri); + } - // Build an array of unique server certs. - if (drmInfo.serverCertificate) { - const found = serverCerts.some( - (cert) => Uint8ArrayUtils.equal(cert, drmInfo.serverCertificate)); - if (!found) { - serverCerts.push(drmInfo.serverCertificate); - } - } + // Build an array of unique server certs. + if (drmInfo.serverCertificate) { + const found = serverCerts.some( + (cert) => Uint8ArrayUtils.equal(cert, drmInfo.serverCertificate)); + if (!found) { + serverCerts.push(drmInfo.serverCertificate); + } + } - // Build an array of unique init datas. - if (drmInfo.initData) { - drmInfo.initData.forEach((initDataOverride) => { - const found = initDatas.some( - (initData) => initDataOverrideEqual(initData, initDataOverride)); - if (!found) { - initDatas.push(initDataOverride); + // Build an array of unique init datas. + if (drmInfo.initData) { + drmInfo.initData.forEach((initDataOverride) => { + const found = initDatas.some( + (initData) => initDataOverrideEqual(initData, initDataOverride)); + if (!found) { + initDatas.push(initDataOverride); + } + }); + } + + if (drmInfo.keyIds) { + for (let i = 0; i < drmInfo.keyIds.length; ++i) { + if (!keyIds.includes(drmInfo.keyIds[i])) { + keyIds.push(drmInfo.keyIds[i]); + } + } } }); - } - - if (drmInfo.keyIds) { - for (let i = 0; i < drmInfo.keyIds.length; ++i) { - if (!keyIds.includes(drmInfo.keyIds[i])) { - keyIds.push(drmInfo.keyIds[i]); - } - } - } - }); -}; + }; /** @@ -2067,8 +2067,8 @@ shaka.media.DrmEngine.closeSession_ = async function(session) { /** @type {boolean} */ const wasSessionClosed = await Promise.race([ - session.close().then(() => true), - timeout.then(() => false), + session.close().then(() => true), + timeout.then(() => false), ]); if (!wasSessionClosed) { diff --git a/lib/media/manifest_parser.js b/lib/media/manifest_parser.js index 8692b7f35..00cb22231 100644 --- a/lib/media/manifest_parser.js +++ b/lib/media/manifest_parser.js @@ -220,7 +220,7 @@ shaka.media.ManifestParser.getFactory_ = async function( } shaka.log.warning('Could not determine manifest type using MIME type', - mimeType); + mimeType); } } diff --git a/lib/media/media_source_engine.js b/lib/media/media_source_engine.js index 230f037f8..82902c8c0 100644 --- a/lib/media/media_source_engine.js +++ b/lib/media/media_source_engine.js @@ -421,7 +421,7 @@ shaka.media.MediaSourceEngine.prototype.isBuffered = function( } else { const buffered = this.getBuffered_(contentType); return shaka.media.TimeRangesUtils.isBuffered( - buffered, time, smallGapLimit); + buffered, time, smallGapLimit); } }; @@ -436,14 +436,14 @@ shaka.media.MediaSourceEngine.prototype.isBuffered = function( */ shaka.media.MediaSourceEngine.prototype.bufferedAheadOf = function(contentType, time) { - const ContentType = shaka.util.ManifestParserUtils.ContentType; - if (contentType == ContentType.TEXT) { - return this.textEngine_.bufferedAheadOf(time); - } else { - const buffered = this.getBuffered_(contentType); - return shaka.media.TimeRangesUtils.bufferedAheadOf(buffered, time); - } -}; + const ContentType = shaka.util.ManifestParserUtils.ContentType; + if (contentType == ContentType.TEXT) { + return this.textEngine_.bufferedAheadOf(time); + } else { + const buffered = this.getBuffered_(contentType); + return shaka.media.TimeRangesUtils.bufferedAheadOf(buffered, time); + } + }; /** @@ -486,7 +486,7 @@ shaka.media.MediaSourceEngine.prototype.getBuffered_ = function(contentType) { // Note: previous MediaSource errors may cause access to |buffered| to // throw. shaka.log.error('failed to get buffered range for ' + contentType, - exception); + exception); } return null; } @@ -509,56 +509,56 @@ shaka.media.MediaSourceEngine.prototype.getBuffered_ = function(contentType) { */ shaka.media.MediaSourceEngine.prototype.appendBuffer = function(contentType, data, startTime, endTime, hasClosedCaptions) { - const ContentType = shaka.util.ManifestParserUtils.ContentType; + const ContentType = shaka.util.ManifestParserUtils.ContentType; - if (contentType == ContentType.TEXT) { - return this.textEngine_.appendBuffer(data, startTime, endTime); - } else if (this.transmuxers_[contentType]) { - return this.transmuxers_[contentType].transmux(data).then( - (transmuxedData) => { - // For HLS CEA-608/708 CLOSED-CAPTIONS, text data is embedded in the - // video stream, so textEngine may not have been initialized. - if (!this.textEngine_) { - this.reinitText('text/vtt'); - } - // This doesn't work for native TS support (ex. Edge/Chromecast), - // since no transmuxing is needed for native TS. - if (transmuxedData.captions) { - const videoOffset = + if (contentType == ContentType.TEXT) { + return this.textEngine_.appendBuffer(data, startTime, endTime); + } else if (this.transmuxers_[contentType]) { + return this.transmuxers_[contentType].transmux(data).then( + (transmuxedData) => { + // For HLS CEA-608/708 CLOSED-CAPTIONS, text data is embedded in the + // video stream, so textEngine may not have been initialized. + if (!this.textEngine_) { + this.reinitText('text/vtt'); + } + // This doesn't work for native TS support (ex. Edge/Chromecast), + // since no transmuxing is needed for native TS. + if (transmuxedData.captions) { + const videoOffset = this.sourceBuffers_[ContentType.VIDEO].timestampOffset; - this.textEngine_.storeAndAppendClosedCaptions( - transmuxedData.captions, startTime, endTime, videoOffset); - } - return this.enqueueOperation_(contentType, - this.append_.bind(this, contentType, transmuxedData.data.buffer)); - }); - } else if (hasClosedCaptions && window.muxjs) { - if (!this.textEngine_) { - this.reinitText('text/vtt'); - } - // If it is the init segment for closed captions, initialize the closed - // caption parser. - if (startTime == null && endTime == null) { - this.captionParser_.init(data); - } else { - this.captionParser_.parseFrom(data, (captions) => { - if (captions.length) { - const videoOffset = - this.sourceBuffers_[ContentType.VIDEO].timestampOffset; - this.textEngine_.storeAndAppendClosedCaptions( - captions, startTime, endTime, videoOffset); + this.textEngine_.storeAndAppendClosedCaptions( + transmuxedData.captions, startTime, endTime, videoOffset); + } + return this.enqueueOperation_(contentType, + this.append_.bind(this, contentType, transmuxedData.data.buffer)); + }); + } else if (hasClosedCaptions && window.muxjs) { + if (!this.textEngine_) { + this.reinitText('text/vtt'); } - }); - } - return this.enqueueOperation_( - contentType, - this.append_.bind(this, contentType, data)); - } else { - return this.enqueueOperation_( - contentType, - this.append_.bind(this, contentType, data)); - } -}; + // If it is the init segment for closed captions, initialize the closed + // caption parser. + if (startTime == null && endTime == null) { + this.captionParser_.init(data); + } else { + this.captionParser_.parseFrom(data, (captions) => { + if (captions.length) { + const videoOffset = + this.sourceBuffers_[ContentType.VIDEO].timestampOffset; + this.textEngine_.storeAndAppendClosedCaptions( + captions, startTime, endTime, videoOffset); + } + }); + } + return this.enqueueOperation_( + contentType, + this.append_.bind(this, contentType, data)); + } else { + return this.enqueueOperation_( + contentType, + this.append_.bind(this, contentType, data)); + } + }; /** @@ -568,10 +568,10 @@ shaka.media.MediaSourceEngine.prototype.appendBuffer = */ shaka.media.MediaSourceEngine.prototype.setSelectedClosedCaptionId = function(id) { - const VIDEO = shaka.util.ManifestParserUtils.ContentType.VIDEO; - const videoBufferEndTime = this.bufferEnd(VIDEO) || 0; - this.textEngine_.setSelectedClosedCaptionId(id, videoBufferEndTime); -}; + const VIDEO = shaka.util.ManifestParserUtils.ContentType.VIDEO; + const videoBufferEndTime = this.bufferEnd(VIDEO) || 0; + this.textEngine_.setSelectedClosedCaptionId(id, videoBufferEndTime); + }; /** @@ -584,18 +584,18 @@ shaka.media.MediaSourceEngine.prototype.setSelectedClosedCaptionId = */ shaka.media.MediaSourceEngine.prototype.remove = function(contentType, startTime, endTime) { - // On IE11, this operation would be permitted, but would have no effect! - // See https://github.com/google/shaka-player/issues/251 - goog.asserts.assert(endTime < Number.MAX_VALUE, - 'remove() with MAX_VALUE or Infinity is not IE-compatible!'); - const ContentType = shaka.util.ManifestParserUtils.ContentType; - if (contentType == ContentType.TEXT) { - return this.textEngine_.remove(startTime, endTime); - } - return this.enqueueOperation_( - contentType, - this.remove_.bind(this, contentType, startTime, endTime)); -}; + // On IE11, this operation would be permitted, but would have no effect! + // See https://github.com/google/shaka-player/issues/251 + goog.asserts.assert(endTime < Number.MAX_VALUE, + 'remove() with MAX_VALUE or Infinity is not IE-compatible!'); + const ContentType = shaka.util.ManifestParserUtils.ContentType; + if (contentType == ContentType.TEXT) { + return this.textEngine_.remove(startTime, endTime); + } + return this.enqueueOperation_( + contentType, + this.remove_.bind(this, contentType, startTime, endTime)); + }; /** @@ -757,9 +757,9 @@ shaka.media.MediaSourceEngine.prototype.getDuration = function() { */ shaka.media.MediaSourceEngine.prototype.append_ = function(contentType, data) { - // This will trigger an 'updateend' event. - this.sourceBuffers_[contentType].appendBuffer(data); -}; + // This will trigger an 'updateend' event. + this.sourceBuffers_[contentType].appendBuffer(data); + }; /** @@ -771,16 +771,16 @@ shaka.media.MediaSourceEngine.prototype.append_ = */ shaka.media.MediaSourceEngine.prototype.remove_ = function(contentType, startTime, endTime) { - if (endTime <= startTime) { - // Ignore removal of inverted or empty ranges. - // Fake 'updateend' event to resolve the operation. - this.onUpdateEnd_(contentType); - return; - } + if (endTime <= startTime) { + // Ignore removal of inverted or empty ranges. + // Fake 'updateend' event to resolve the operation. + this.onUpdateEnd_(contentType); + return; + } - // This will trigger an 'updateend' event. - this.sourceBuffers_[contentType].remove(startTime, endTime); -}; + // This will trigger an 'updateend' event. + this.sourceBuffers_[contentType].remove(startTime, endTime); + }; /** @@ -837,18 +837,18 @@ shaka.media.MediaSourceEngine.prototype.flush_ = function(contentType) { */ shaka.media.MediaSourceEngine.prototype.setTimestampOffset_ = function(contentType, timestampOffset) { - // Work around for https://github.com/google/shaka-player/issues/1281: - // TODO(https://bit.ly/2ttKiBU): follow up when this is fixed in Edge - if (timestampOffset < 0) { - // Try to prevent rounding errors in Edge from removing the first keyframe. - timestampOffset += 0.001; - } + // Work around for https://github.com/google/shaka-player/issues/1281: + // TODO(https://bit.ly/2ttKiBU): follow up when this is fixed in Edge + if (timestampOffset < 0) { + // Try to prevent rounding errors in Edge from removing the first keyframe. + timestampOffset += 0.001; + } - this.sourceBuffers_[contentType].timestampOffset = timestampOffset; + this.sourceBuffers_[contentType].timestampOffset = timestampOffset; - // Fake an 'updateend' event to resolve the operation. - this.onUpdateEnd_(contentType); -}; + // Fake an 'updateend' event to resolve the operation. + this.onUpdateEnd_(contentType); + }; /** @@ -860,16 +860,16 @@ shaka.media.MediaSourceEngine.prototype.setTimestampOffset_ = */ shaka.media.MediaSourceEngine.prototype.setAppendWindow_ = function(contentType, appendWindowStart, appendWindowEnd) { - // You can't set start > end, so first set start to 0, then set the new end, - // then set the new start. That way, there are no intermediate states which - // are invalid. - this.sourceBuffers_[contentType].appendWindowStart = 0; - this.sourceBuffers_[contentType].appendWindowEnd = appendWindowEnd; - this.sourceBuffers_[contentType].appendWindowStart = appendWindowStart; + // You can't set start > end, so first set start to 0, then set the new end, + // then set the new start. That way, there are no intermediate states which + // are invalid. + this.sourceBuffers_[contentType].appendWindowStart = 0; + this.sourceBuffers_[contentType].appendWindowEnd = appendWindowEnd; + this.sourceBuffers_[contentType].appendWindowStart = appendWindowStart; - // Fake an 'updateend' event to resolve the operation. - this.onUpdateEnd_(contentType); -}; + // Fake an 'updateend' event to resolve the operation. + this.onUpdateEnd_(contentType); + }; /** @@ -879,22 +879,22 @@ shaka.media.MediaSourceEngine.prototype.setAppendWindow_ = */ shaka.media.MediaSourceEngine.prototype.onError_ = function(contentType, event) { - const operation = this.queues_[contentType][0]; - goog.asserts.assert(operation, 'Spurious error event!'); - goog.asserts.assert(!this.sourceBuffers_[contentType].updating, - 'SourceBuffer should not be updating on error!'); - const code = this.video_.error ? this.video_.error.code : 0; - operation.p.reject(new shaka.util.Error( - shaka.util.Error.Severity.CRITICAL, - shaka.util.Error.Category.MEDIA, - shaka.util.Error.Code.MEDIA_SOURCE_OPERATION_FAILED, - code)); - // Do not pop from queue. An 'updateend' event will fire next, and to avoid - // synchronizing these two event handlers, we will allow that one to pop from - // the queue as normal. Note that because the operation has already been - // rejected, the call to resolve() in the 'updateend' handler will have no - // effect. -}; + const operation = this.queues_[contentType][0]; + goog.asserts.assert(operation, 'Spurious error event!'); + goog.asserts.assert(!this.sourceBuffers_[contentType].updating, + 'SourceBuffer should not be updating on error!'); + const code = this.video_.error ? this.video_.error.code : 0; + operation.p.reject(new shaka.util.Error( + shaka.util.Error.Severity.CRITICAL, + shaka.util.Error.Category.MEDIA, + shaka.util.Error.Code.MEDIA_SOURCE_OPERATION_FAILED, + code)); + // Do not pop from queue. An 'updateend' event will fire next, and to avoid + // synchronizing these two event handlers, we will allow that one to pop from + // the queue as normal. Note that because the operation has already been + // rejected, the call to resolve() in the 'updateend' handler will have no + // effect. + }; /** @@ -908,7 +908,7 @@ shaka.media.MediaSourceEngine.prototype.onUpdateEnd_ = function(contentType) { return; } goog.asserts.assert(!this.sourceBuffers_[contentType].updating, - 'SourceBuffer should not be updating on updateend!'); + 'SourceBuffer should not be updating on updateend!'); operation.p.resolve(); this.popFromQueue_(contentType); }; @@ -924,38 +924,38 @@ shaka.media.MediaSourceEngine.prototype.onUpdateEnd_ = function(contentType) { */ shaka.media.MediaSourceEngine.prototype.enqueueOperation_ = function(contentType, start) { - if (this.destroyed_) { - return Promise.reject(); - } - - const operation = { - start: start, - p: new shaka.util.PublicPromise(), - }; - this.queues_[contentType].push(operation); - - if (this.queues_[contentType].length == 1) { - try { - operation.start(); - } catch (exception) { - if (exception.name == 'QuotaExceededError') { - operation.p.reject(new shaka.util.Error( - shaka.util.Error.Severity.CRITICAL, - shaka.util.Error.Category.MEDIA, - shaka.util.Error.Code.QUOTA_EXCEEDED_ERROR, - contentType)); - } else { - operation.p.reject(new shaka.util.Error( - shaka.util.Error.Severity.CRITICAL, - shaka.util.Error.Category.MEDIA, - shaka.util.Error.Code.MEDIA_SOURCE_OPERATION_THREW, - exception)); + if (this.destroyed_) { + return Promise.reject(); } - this.popFromQueue_(contentType); - } - } - return operation.p; -}; + + const operation = { + start: start, + p: new shaka.util.PublicPromise(), + }; + this.queues_[contentType].push(operation); + + if (this.queues_[contentType].length == 1) { + try { + operation.start(); + } catch (exception) { + if (exception.name == 'QuotaExceededError') { + operation.p.reject(new shaka.util.Error( + shaka.util.Error.Severity.CRITICAL, + shaka.util.Error.Category.MEDIA, + shaka.util.Error.Code.QUOTA_EXCEEDED_ERROR, + contentType)); + } else { + operation.p.reject(new shaka.util.Error( + shaka.util.Error.Severity.CRITICAL, + shaka.util.Error.Category.MEDIA, + shaka.util.Error.Code.MEDIA_SOURCE_OPERATION_THREW, + exception)); + } + this.popFromQueue_(contentType); + } + } + return operation.p; + }; /** @@ -968,83 +968,83 @@ shaka.media.MediaSourceEngine.prototype.enqueueOperation_ = */ shaka.media.MediaSourceEngine.prototype.enqueueBlockingOperation_ = function(run) { - if (this.destroyed_) { - return Promise.reject(); - } - - const allWaiters = []; - - // Enqueue a 'wait' operation onto each queue. - // This operation signals its readiness when it starts. - // When all wait operations are ready, the real operation takes place. - for (const contentType in this.sourceBuffers_) { - const ready = new shaka.util.PublicPromise(); - const operation = { - start: function(ready) { ready.resolve(); }.bind(null, ready), - p: ready, - }; - - this.queues_[contentType].push(operation); - allWaiters.push(ready); - - if (this.queues_[contentType].length == 1) { - operation.start(); - } - } - - // Return a Promise to the real operation, which waits to begin until there - // are no other in-progress operations on any SourceBuffers. - return Promise.all(allWaiters).then(() => { - if (goog.DEBUG) { - // If we did it correctly, nothing is updating. - for (const contentType in this.sourceBuffers_) { - goog.asserts.assert( - this.sourceBuffers_[contentType].updating == false, - 'SourceBuffers should not be updating after a blocking op!'); + if (this.destroyed_) { + return Promise.reject(); } - } - let ret; - // Run the real operation, which is synchronous. - try { - run(); - } catch (exception) { - ret = Promise.reject(new shaka.util.Error( - shaka.util.Error.Severity.CRITICAL, - shaka.util.Error.Category.MEDIA, - shaka.util.Error.Code.MEDIA_SOURCE_OPERATION_THREW, - exception)); - } + const allWaiters = []; - // Unblock the queues. - for (const contentType in this.sourceBuffers_) { - this.popFromQueue_(contentType); - } - - return ret; - }, () => { - // One of the waiters failed, which means we've been destroyed. - goog.asserts.assert(this.destroyed_, 'Should be destroyed by now'); - // We haven't popped from the queue. Canceled waiters have been removed by - // destroy. What's left now should just be resolved waiters. In uncompiled - // mode, we will maintain good hygiene and make sure the assert at the end - // of destroy passes. In compiled mode, the queues are wiped in destroy. - if (goog.DEBUG) { + // Enqueue a 'wait' operation onto each queue. + // This operation signals its readiness when it starts. + // When all wait operations are ready, the real operation takes place. for (const contentType in this.sourceBuffers_) { - if (this.queues_[contentType].length) { - goog.asserts.assert( - this.queues_[contentType].length == 1, - 'Should be at most one item in queue!'); - goog.asserts.assert( - allWaiters.includes(this.queues_[contentType][0].p), - 'The item in queue should be one of our waiters!'); - this.queues_[contentType].shift(); + const ready = new shaka.util.PublicPromise(); + const operation = { + start: function(ready) { ready.resolve(); }.bind(null, ready), + p: ready, + }; + + this.queues_[contentType].push(operation); + allWaiters.push(ready); + + if (this.queues_[contentType].length == 1) { + operation.start(); } } - } - return Promise.reject(); - }); -}; + + // Return a Promise to the real operation, which waits to begin until there + // are no other in-progress operations on any SourceBuffers. + return Promise.all(allWaiters).then(() => { + if (goog.DEBUG) { + // If we did it correctly, nothing is updating. + for (const contentType in this.sourceBuffers_) { + goog.asserts.assert( + this.sourceBuffers_[contentType].updating == false, + 'SourceBuffers should not be updating after a blocking op!'); + } + } + + let ret; + // Run the real operation, which is synchronous. + try { + run(); + } catch (exception) { + ret = Promise.reject(new shaka.util.Error( + shaka.util.Error.Severity.CRITICAL, + shaka.util.Error.Category.MEDIA, + shaka.util.Error.Code.MEDIA_SOURCE_OPERATION_THREW, + exception)); + } + + // Unblock the queues. + for (const contentType in this.sourceBuffers_) { + this.popFromQueue_(contentType); + } + + return ret; + }, () => { + // One of the waiters failed, which means we've been destroyed. + goog.asserts.assert(this.destroyed_, 'Should be destroyed by now'); + // We haven't popped from the queue. Canceled waiters have been removed by + // destroy. What's left now should just be resolved waiters. In uncompiled + // mode, we will maintain good hygiene and make sure the assert at the end + // of destroy passes. In compiled mode, the queues are wiped in destroy. + if (goog.DEBUG) { + for (const contentType in this.sourceBuffers_) { + if (this.queues_[contentType].length) { + goog.asserts.assert( + this.queues_[contentType].length == 1, + 'Should be at most one item in queue!'); + goog.asserts.assert( + allWaiters.includes(this.queues_[contentType][0].p), + 'The item in queue should be one of our waiters!'); + this.queues_[contentType].shift(); + } + } + } + return Promise.reject(); + }); + }; /** diff --git a/lib/media/playhead.js b/lib/media/playhead.js index 9de5365fc..0f1d30f8e 100644 --- a/lib/media/playhead.js +++ b/lib/media/playhead.js @@ -370,7 +370,7 @@ shaka.media.MediaSourcePlayhead = class { const duration = this.timeline_.getDuration(); if (time >= duration) { goog.asserts.assert(this.config_.durationBackoff >= 0, - 'Duration backoff must be non-negative!'); + 'Duration backoff must be non-negative!'); return duration - this.config_.durationBackoff; } return time; diff --git a/lib/media/presentation_timeline.js b/lib/media/presentation_timeline.js index 590f4ee5c..77c0193d8 100644 --- a/lib/media/presentation_timeline.js +++ b/lib/media/presentation_timeline.js @@ -135,8 +135,8 @@ shaka.media.PresentationTimeline.prototype.setDuration = function(duration) { */ shaka.media.PresentationTimeline.prototype.getPresentationStartTime = function() { - return this.presentationStartTime_; -}; + return this.presentationStartTime_; + }; /** @@ -175,10 +175,10 @@ shaka.media.PresentationTimeline.prototype.setStatic = function(isStatic) { */ shaka.media.PresentationTimeline.prototype.setSegmentAvailabilityDuration = function(segmentAvailabilityDuration) { - goog.asserts.assert(segmentAvailabilityDuration >= 0, - 'segmentAvailabilityDuration must be >= 0'); - this.segmentAvailabilityDuration_ = segmentAvailabilityDuration; -}; + goog.asserts.assert(segmentAvailabilityDuration >= 0, + 'segmentAvailabilityDuration must be >= 0'); + this.segmentAvailabilityDuration_ = segmentAvailabilityDuration; + }; /** @@ -247,7 +247,7 @@ shaka.media.PresentationTimeline.prototype.notifySegments = function( } shaka.log.v1('notifySegments:', - 'maxSegmentDuration=' + this.maxSegmentDuration_); + 'maxSegmentDuration=' + this.maxSegmentDuration_); }; @@ -286,7 +286,7 @@ shaka.media.PresentationTimeline.prototype.notifyMaxSegmentDuration = function( this.maxSegmentDuration_, maxSegmentDuration); shaka.log.v1('notifyNewSegmentDuration:', - 'maxSegmentDuration=' + this.maxSegmentDuration_); + 'maxSegmentDuration=' + this.maxSegmentDuration_); }; @@ -339,17 +339,17 @@ shaka.media.PresentationTimeline.prototype.isInProgress = function() { */ shaka.media.PresentationTimeline.prototype.getSegmentAvailabilityStart = function() { - goog.asserts.assert(this.segmentAvailabilityDuration_ >= 0, - 'The availability duration should be positive'); + goog.asserts.assert(this.segmentAvailabilityDuration_ >= 0, + 'The availability duration should be positive'); - if (this.segmentAvailabilityDuration_ == Infinity) { - return this.userSeekStart_; - } + if (this.segmentAvailabilityDuration_ == Infinity) { + return this.userSeekStart_; + } - const end = this.getSegmentAvailabilityEnd(); - const start = end - this.segmentAvailabilityDuration_; - return Math.max(this.userSeekStart_, start); -}; + const end = this.getSegmentAvailabilityEnd(); + const start = end - this.segmentAvailabilityDuration_; + return Math.max(this.userSeekStart_, start); + }; /** @@ -361,8 +361,8 @@ shaka.media.PresentationTimeline.prototype.getSegmentAvailabilityStart = */ shaka.media.PresentationTimeline.prototype.setUserSeekStart = function(time) { - this.userSeekStart_ = time; -}; + this.userSeekStart_ = time; + }; /** @@ -376,12 +376,12 @@ shaka.media.PresentationTimeline.prototype.setUserSeekStart = */ shaka.media.PresentationTimeline.prototype.getSegmentAvailabilityEnd = function() { - if (!this.isLive() && !this.isInProgress()) { - return this.duration_; - } + if (!this.isLive() && !this.isInProgress()) { + return this.duration_; + } - return Math.min(this.getLiveEdge_(), this.duration_); -}; + return Math.min(this.getLiveEdge_(), this.duration_); + }; /** @@ -454,20 +454,20 @@ shaka.media.PresentationTimeline.prototype.getSeekRangeEnd = function() { */ shaka.media.PresentationTimeline.prototype.usingPresentationStartTime = function() { - // If it's VOD, IPR, or an HLS "event", we are not using the presentation - // start time. - if (this.presentationStartTime_ == null) { - return false; - } + // If it's VOD, IPR, or an HLS "event", we are not using the presentation + // start time. + if (this.presentationStartTime_ == null) { + return false; + } - // If we have explicit segment times, we're not using the presentation - // start time. - if (this.maxSegmentEndTime_ != null) { - return false; - } + // If we have explicit segment times, we're not using the presentation + // start time. + if (this.maxSegmentEndTime_ != null) { + return false; + } - return true; -}; + return true; + }; /** @@ -476,7 +476,7 @@ shaka.media.PresentationTimeline.prototype.usingPresentationStartTime = */ shaka.media.PresentationTimeline.prototype.getLiveEdge_ = function() { goog.asserts.assert(this.presentationStartTime_ != null, - 'Cannot compute timeline live edge without start time'); + 'Cannot compute timeline live edge without start time'); // Date.now() is in milliseconds, from which we compute "now" in seconds. const now = (Date.now() + this.clockOffset_) / 1000.0; return Math.max( @@ -500,14 +500,14 @@ if (goog.DEBUG) { // IPR streams should have a start time, and segments should not expire. goog.asserts.assert(this.presentationStartTime_ != null && this.segmentAvailabilityDuration_ == Infinity, - 'Detected as IPR stream, but does not match our model of IPR!'); + 'Detected as IPR stream, but does not match our model of IPR!'); } else { // VOD // VOD segments should not expire and the presentation should be finite // and static. goog.asserts.assert(this.segmentAvailabilityDuration_ == Infinity && this.duration_ != Infinity && this.static_, - 'Detected as VOD stream, but does not match our model of VOD!'); + 'Detected as VOD stream, but does not match our model of VOD!'); } }; } diff --git a/lib/media/segment_index.js b/lib/media/segment_index.js index 1dba44a67..377c61f1c 100644 --- a/lib/media/segment_index.js +++ b/lib/media/segment_index.js @@ -169,7 +169,7 @@ shaka.media.SegmentIndex.prototype.merge = function(references) { goog.asserts.assert(r2.endTime > r1.endTime && i == this.references_.length - 1 && j == references.length - 1, - 'This should be an update of the last segment in a period'); + 'This should be an update of the last segment in a period'); const r = new shaka.media.SegmentReference(r1.position, r2.startTime, r2.endTime, r2.getUris, r2.startByte, r2.endByte); newReferences.push(r); @@ -253,9 +253,9 @@ shaka.media.SegmentIndex.prototype.evict = function(time) { */ shaka.media.SegmentIndex.prototype.fit = function(periodDuration) { goog.asserts.assert(periodDuration != null, - 'Period duration must be known for static content!'); + 'Period duration must be known for static content!'); goog.asserts.assert(periodDuration != Infinity, - 'Period duration must be finite for static content!'); + 'Period duration must be finite for static content!'); // Trim out references we will never use. while (this.references_.length) { diff --git a/lib/media/segment_reference.js b/lib/media/segment_reference.js index d93bb7e54..acc0140ad 100644 --- a/lib/media/segment_reference.js +++ b/lib/media/segment_reference.js @@ -128,9 +128,9 @@ shaka.media.InitSegmentReference.prototype.getSize = function() { shaka.media.SegmentReference = function( position, startTime, endTime, uris, startByte, endByte) { goog.asserts.assert(startTime < endTime, - 'startTime must be less than endTime'); + 'startTime must be less than endTime'); goog.asserts.assert((startByte < endByte) || (endByte == null), - 'startByte must be < endByte'); + 'startByte must be < endByte'); /** @const {number} */ this.position = position; diff --git a/lib/media/streaming_engine.js b/lib/media/streaming_engine.js index 3911a1647..5437ab347 100644 --- a/lib/media/streaming_engine.js +++ b/lib/media/streaming_engine.js @@ -587,8 +587,8 @@ shaka.media.StreamingEngine.prototype.loadNewTextStream = async function( const needPeriodIndex = this.findPeriodForTime_(presentationTime); const state = this.createMediaState_(stream, - needPeriodIndex, - /* resumeAt= */ 0); + needPeriodIndex, + /* resumeAt= */ 0); this.mediaStates_.set(ContentType.TEXT, state); this.scheduleUpdate_(state, 0); @@ -664,13 +664,13 @@ shaka.media.StreamingEngine.prototype.setTrickPlay = function(on) { */ shaka.media.StreamingEngine.prototype.switchVariant = function(variant, clearBuffer, safeMargin) { - if (variant.video) { - this.switchInternal_(variant.video, clearBuffer, safeMargin); - } - if (variant.audio) { - this.switchInternal_(variant.audio, clearBuffer, safeMargin); - } -}; + if (variant.video) { + this.switchInternal_(variant.video, clearBuffer, safeMargin); + } + if (variant.audio) { + this.switchInternal_(variant.audio, clearBuffer, safeMargin); + } + }; /** @@ -679,7 +679,7 @@ shaka.media.StreamingEngine.prototype.switchVariant = shaka.media.StreamingEngine.prototype.switchTextStream = function(textStream) { const ContentType = shaka.util.ManifestParserUtils.ContentType; goog.asserts.assert(textStream && textStream.type == ContentType.TEXT, - 'Wrong stream type passed to switchTextStream!'); + 'Wrong stream type passed to switchTextStream!'); this.switchInternal_(textStream, /* clearBuffer */ true, /* safeMargin */ 0); }; @@ -751,7 +751,7 @@ shaka.media.StreamingEngine.prototype.switchInternal_ = function( // Sanity check. If the Period is ready then the Stream should be ready too. canSwitchRecord = this.canSwitchStream_.get(stream.id); goog.asserts.assert(canSwitchRecord && canSwitchRecord.resolved, - 'switch: expected Stream ' + stream.id + ' to be ready'); + 'switch: expected Stream ' + stream.id + ' to be ready'); if (!canSwitchRecord || !canSwitchRecord.resolved) { return; } @@ -814,37 +814,37 @@ shaka.media.StreamingEngine.prototype.switchInternal_ = function( */ shaka.media.StreamingEngine.prototype.shouldAbortCurrentRequest_ = function(mediaState, periodIndex) { - // If the operation is completed, it will be set to null, and there's no need - // to abort the request. - if (!mediaState.operation) { - return false; - } + // If the operation is completed, it will be set to null, and there's no need + // to abort the request. + if (!mediaState.operation) { + return false; + } - const presentationTime = this.playerInterface_.getPresentationTime(); - const bufferEnd = + const presentationTime = this.playerInterface_.getPresentationTime(); + const bufferEnd = this.playerInterface_.mediaSourceEngine.bufferEnd(mediaState.type); - // The next segment to append from the current stream. This doesn't account - // for a pending network request and will likely be different from that since - // we just switched. - const newSegment = this.getSegmentReferenceNeeded_( - mediaState, presentationTime, bufferEnd, periodIndex); - let newSegmentSize = newSegment ? newSegment.getSize() : null; - if (newSegmentSize == null) { - return false; - } + // The next segment to append from the current stream. This doesn't account + // for a pending network request and will likely be different from that since + // we just switched. + const newSegment = this.getSegmentReferenceNeeded_( + mediaState, presentationTime, bufferEnd, periodIndex); + let newSegmentSize = newSegment ? newSegment.getSize() : null; + if (newSegmentSize == null) { + return false; + } - // When switching, we'll need to download the init segment. - const init = mediaState.stream.initSegmentReference; - if (init) { - newSegmentSize += init.getSize() || 0; - } + // When switching, we'll need to download the init segment. + const init = mediaState.stream.initSegmentReference; + if (init) { + newSegmentSize += init.getSize() || 0; + } - // TODO: if we have downloaded most of the segment, ex. 95%, we should not - // abort the current request. - const bytesRemaining = mediaState.operation.getBytesRemaining(); - return bytesRemaining > newSegmentSize; -}; + // TODO: if we have downloaded most of the segment, ex. 95%, we should not + // abort the current request. + const bytesRemaining = mediaState.operation.getBytesRemaining(); + return bytesRemaining > newSegmentSize; + }; /** @@ -1346,9 +1346,9 @@ shaka.media.StreamingEngine.prototype.update_ = function(mediaState) { mediaState.type, presentationTime); shaka.log.v2(logPrefix, - 'update_:', - 'presentationTime=' + presentationTime, - 'bufferedAhead=' + bufferedAhead); + 'update_:', + 'presentationTime=' + presentationTime, + 'bufferedAhead=' + bufferedAhead); const unscaledBufferingGoal = Math.max( this.manifest_.minBufferTime || 0, @@ -1386,10 +1386,10 @@ shaka.media.StreamingEngine.prototype.update_ = function(mediaState) { mediaState.needPeriodIndex = needPeriodIndex; if (needPeriodIndex != currentPeriodIndex) { shaka.log.debug(logPrefix, - 'need Period ' + needPeriodIndex, - 'presentationTime=' + presentationTime, - 'timeNeeded=' + timeNeeded, - 'currentPeriodIndex=' + currentPeriodIndex); + 'need Period ' + needPeriodIndex, + 'presentationTime=' + presentationTime, + 'timeNeeded=' + timeNeeded, + 'currentPeriodIndex=' + currentPeriodIndex); return null; } @@ -1442,9 +1442,9 @@ shaka.media.StreamingEngine.prototype.update_ = function(mediaState) { mediaState.resumeAt = 0; this.fetchAndAppend_(mediaState, - presentationTime, - currentPeriodIndex, - reference); + presentationTime, + currentPeriodIndex, + reference); return null; }; @@ -1565,18 +1565,18 @@ shaka.media.StreamingEngine.prototype.lookupSegmentPosition_ = function( const currentPeriod = this.manifest_.periods[currentPeriodIndex]; shaka.log.debug(logPrefix, - 'looking up segment:', - 'presentationTime=' + presentationTime, - 'currentPeriod.startTime=' + currentPeriod.startTime); + 'looking up segment:', + 'presentationTime=' + presentationTime, + 'currentPeriod.startTime=' + currentPeriod.startTime); const lookupTime = Math.max(0, presentationTime - currentPeriod.startTime); const position = mediaState.stream.findSegmentPosition(lookupTime); if (position == null) { shaka.log.warning(logPrefix, - 'cannot find segment:', - 'currentPeriod.startTime=' + currentPeriod.startTime, - 'lookupTime=' + lookupTime); + 'cannot find segment:', + 'currentPeriod.startTime=' + currentPeriod.startTime, + 'lookupTime=' + lookupTime); } return position; @@ -1595,36 +1595,36 @@ shaka.media.StreamingEngine.prototype.lookupSegmentPosition_ = function( */ shaka.media.StreamingEngine.prototype.getSegmentReferenceIfAvailable_ = function(mediaState, currentPeriodIndex, position) { - const logPrefix = shaka.media.StreamingEngine.logPrefix_(mediaState); - const currentPeriod = this.manifest_.periods[currentPeriodIndex]; + const logPrefix = shaka.media.StreamingEngine.logPrefix_(mediaState); + const currentPeriod = this.manifest_.periods[currentPeriodIndex]; - const reference = mediaState.stream.getSegmentReference(position); - if (!reference) { - shaka.log.v1(logPrefix, - 'segment does not exist:', - 'currentPeriod.startTime=' + currentPeriod.startTime, - 'position=' + position); - return null; - } + const reference = mediaState.stream.getSegmentReference(position); + if (!reference) { + shaka.log.v1(logPrefix, + 'segment does not exist:', + 'currentPeriod.startTime=' + currentPeriod.startTime, + 'position=' + position); + return null; + } - const timeline = this.manifest_.presentationTimeline; - const availabilityStart = timeline.getSegmentAvailabilityStart(); - const availabilityEnd = timeline.getSegmentAvailabilityEnd(); + const timeline = this.manifest_.presentationTimeline; + const availabilityStart = timeline.getSegmentAvailabilityStart(); + const availabilityEnd = timeline.getSegmentAvailabilityEnd(); - if ((currentPeriod.startTime + reference.endTime < availabilityStart) || + if ((currentPeriod.startTime + reference.endTime < availabilityStart) || (currentPeriod.startTime + reference.startTime > availabilityEnd)) { - shaka.log.v2(logPrefix, - 'segment is not available:', - 'currentPeriod.startTime=' + currentPeriod.startTime, - 'reference.startTime=' + reference.startTime, - 'reference.endTime=' + reference.endTime, - 'availabilityStart=' + availabilityStart, - 'availabilityEnd=' + availabilityEnd); - return null; - } + shaka.log.v2(logPrefix, + 'segment is not available:', + 'currentPeriod.startTime=' + currentPeriod.startTime, + 'reference.startTime=' + reference.startTime, + 'reference.endTime=' + reference.endTime, + 'availabilityStart=' + availabilityStart, + 'availabilityEnd=' + availabilityEnd); + return null; + } - return reference; -}; + return reference; + }; /** @@ -1646,12 +1646,12 @@ shaka.media.StreamingEngine.prototype.fetchAndAppend_ = function( const currentPeriod = this.manifest_.periods[currentPeriodIndex]; shaka.log.v1(logPrefix, - 'fetchAndAppend_:', - 'presentationTime=' + presentationTime, - 'currentPeriod.startTime=' + currentPeriod.startTime, - 'reference.position=' + reference.position, - 'reference.startTime=' + reference.startTime, - 'reference.endTime=' + reference.endTime); + 'fetchAndAppend_:', + 'presentationTime=' + presentationTime, + 'currentPeriod.startTime=' + currentPeriod.startTime, + 'reference.position=' + reference.position, + 'reference.startTime=' + reference.startTime, + 'reference.endTime=' + reference.endTime); // Subtlety: The playhead may move while asynchronous update operations are // in progress, so we should avoid calling playhead.getTime() in any @@ -1694,11 +1694,11 @@ shaka.media.StreamingEngine.prototype.fetchAndAppend_ = function( return null; } return this.append_(mediaState, - presentationTime, - currentPeriod, - stream, - reference, - results[1]); + presentationTime, + currentPeriod, + stream, + reference, + results[1]); }).then(() => { if (this.destroyed_ || this.fatalError_) { return; @@ -1725,7 +1725,7 @@ shaka.media.StreamingEngine.prototype.fetchAndAppend_ = function( return; } goog.asserts.assert(error instanceof shaka.util.Error, - 'Should only receive a Shaka error'); + 'Should only receive a Shaka error'); mediaState.performingUpdate = false; @@ -1884,7 +1884,7 @@ shaka.media.StreamingEngine.prototype.initSourceBuffer_ = function( currentPeriod.startTime - mediaState.stream.presentationTimeOffset; shaka.log.v1(logPrefix, 'setting timestamp offset to ' + timestampOffset); shaka.log.v1(logPrefix, - 'setting append window start to ' + appendWindowStart); + 'setting append window start to ' + appendWindowStart); shaka.log.v1(logPrefix, 'setting append window end to ' + appendWindowEnd); const setStreamProperties = this.playerInterface_.mediaSourceEngine.setStreamProperties( @@ -2049,9 +2049,9 @@ shaka.media.StreamingEngine.prototype.evict_ = function( this.playerInterface_.mediaSourceEngine.bufferStart(mediaState.type); if (startTime == null) { shaka.log.v2(logPrefix, - 'buffer behind okay because nothing buffered:', - 'presentationTime=' + presentationTime, - 'bufferBehind=' + bufferBehind); + 'buffer behind okay because nothing buffered:', + 'presentationTime=' + presentationTime, + 'bufferBehind=' + bufferBehind); return Promise.resolve(); } const bufferedBehind = presentationTime - startTime; @@ -2059,20 +2059,20 @@ shaka.media.StreamingEngine.prototype.evict_ = function( const overflow = bufferedBehind - bufferBehind; if (overflow <= 0) { shaka.log.v2(logPrefix, - 'buffer behind okay:', - 'presentationTime=' + presentationTime, - 'bufferedBehind=' + bufferedBehind, - 'bufferBehind=' + bufferBehind, - 'underflow=' + (-overflow)); + 'buffer behind okay:', + 'presentationTime=' + presentationTime, + 'bufferedBehind=' + bufferedBehind, + 'bufferBehind=' + bufferBehind, + 'underflow=' + (-overflow)); return Promise.resolve(); } shaka.log.v1(logPrefix, - 'buffer behind too large:', - 'presentationTime=' + presentationTime, - 'bufferedBehind=' + bufferedBehind, - 'bufferBehind=' + bufferBehind, - 'overflow=' + overflow); + 'buffer behind too large:', + 'presentationTime=' + presentationTime, + 'bufferedBehind=' + bufferedBehind, + 'bufferBehind=' + bufferBehind, + 'overflow=' + overflow); return this.playerInterface_.mediaSourceEngine.remove( mediaState.type, startTime, startTime + overflow).then(() => { @@ -2241,7 +2241,7 @@ shaka.media.StreamingEngine.prototype.handlePeriodTransition_ = function( if (!allReady) { // TODO: Write unit tests for this case. shaka.log.debug(logPrefix, 'ignoring transition to Period', - needPeriodIndex, 'since another is happening'); + needPeriodIndex, 'since another is happening'); return; } @@ -2269,7 +2269,7 @@ shaka.media.StreamingEngine.prototype.handlePeriodTransition_ = function( } shaka.log.error(logPrefix, - 'invalid Streams chosen: missing ' + type + ' Stream'); + 'invalid Streams chosen: missing ' + type + ' Stream'); this.playerInterface_.onError(new shaka.util.Error( shaka.util.Error.Severity.CRITICAL, shaka.util.Error.Category.STREAMING, @@ -2296,7 +2296,7 @@ shaka.media.StreamingEngine.prototype.handlePeriodTransition_ = function( } shaka.log.error(logPrefix, - 'invalid Streams chosen: unusable ' + type + ' Stream'); + 'invalid Streams chosen: unusable ' + type + ' Stream'); this.playerInterface_.onError(new shaka.util.Error( shaka.util.Error.Severity.CRITICAL, shaka.util.Error.Category.STREAMING, @@ -2452,48 +2452,48 @@ shaka.media.StreamingEngine.prototype.fetch_ = function(mediaState, reference) { */ shaka.media.StreamingEngine.prototype.clearBuffer_ = async function(mediaState, flush, safeMargin) { - const logPrefix = shaka.media.StreamingEngine.logPrefix_(mediaState); + const logPrefix = shaka.media.StreamingEngine.logPrefix_(mediaState); - goog.asserts.assert( - !mediaState.performingUpdate && (mediaState.updateTimer == null), - logPrefix + ' unexpected call to clearBuffer_()'); + goog.asserts.assert( + !mediaState.performingUpdate && (mediaState.updateTimer == null), + logPrefix + ' unexpected call to clearBuffer_()'); - mediaState.waitingToClearBuffer = false; - mediaState.waitingToFlushBuffer = false; - mediaState.clearBufferSafeMargin = 0; - mediaState.clearingBuffer = true; + mediaState.waitingToClearBuffer = false; + mediaState.waitingToFlushBuffer = false; + mediaState.clearBufferSafeMargin = 0; + mediaState.clearingBuffer = true; - shaka.log.debug(logPrefix, 'clearing buffer'); - let p; - if (safeMargin) { - const presentationTime = this.playerInterface_.getPresentationTime(); - const duration = this.playerInterface_.mediaSourceEngine.getDuration(); - p = this.playerInterface_.mediaSourceEngine.remove( - mediaState.type, presentationTime + safeMargin, duration); - } else { - p = this.playerInterface_.mediaSourceEngine.clear(mediaState.type).then( - () => { - if (!this.destroyed_ && flush) { - return this.playerInterface_.mediaSourceEngine.flush( - mediaState.type); - } else { - return null; - } - }); - } + shaka.log.debug(logPrefix, 'clearing buffer'); + let p; + if (safeMargin) { + const presentationTime = this.playerInterface_.getPresentationTime(); + const duration = this.playerInterface_.mediaSourceEngine.getDuration(); + p = this.playerInterface_.mediaSourceEngine.remove( + mediaState.type, presentationTime + safeMargin, duration); + } else { + p = this.playerInterface_.mediaSourceEngine.clear(mediaState.type).then( + () => { + if (!this.destroyed_ && flush) { + return this.playerInterface_.mediaSourceEngine.flush( + mediaState.type); + } else { + return null; + } + }); + } - await p; - if (this.destroyed_) { - return; - } + await p; + if (this.destroyed_) { + return; + } - shaka.log.debug(logPrefix, 'cleared buffer'); - mediaState.lastStream = null; - mediaState.lastSegmentReference = null; - mediaState.clearingBuffer = false; - mediaState.endOfStream = false; - this.scheduleUpdate_(mediaState, 0); -}; + shaka.log.debug(logPrefix, 'cleared buffer'); + mediaState.lastStream = null; + mediaState.lastSegmentReference = null; + mediaState.clearingBuffer = false; + mediaState.endOfStream = false; + this.scheduleUpdate_(mediaState, 0); + }; /** @@ -2508,7 +2508,7 @@ shaka.media.StreamingEngine.prototype.scheduleUpdate_ = function( const logPrefix = shaka.media.StreamingEngine.logPrefix_(mediaState); shaka.log.v2(logPrefix, 'updating in ' + delay + ' seconds'); goog.asserts.assert(mediaState.updateTimer == null, - logPrefix + ' did not expect update to be scheduled'); + logPrefix + ' did not expect update to be scheduled'); mediaState.updateTimer = new shaka.util.DelayedTick(() => { this.onUpdate_(mediaState); diff --git a/lib/media/transmuxer.js b/lib/media/transmuxer.js index ad6f92da7..3c7c0c163 100644 --- a/lib/media/transmuxer.js +++ b/lib/media/transmuxer.js @@ -83,7 +83,7 @@ shaka.media.Transmuxer.isSupported = function(mimeType, contentType) { } const ContentType = shaka.util.ManifestParserUtils.ContentType; return MediaSource.isTypeSupported( - convertTsCodecs(ContentType.AUDIO, mimeType)) || + convertTsCodecs(ContentType.AUDIO, mimeType)) || MediaSource.isTypeSupported(convertTsCodecs(ContentType.VIDEO, mimeType)); }; @@ -128,14 +128,14 @@ shaka.media.Transmuxer.convertTsCodecs = function(contentType, tsMimeType) { newCodecString += '4d00'; } else { goog.asserts.assert(profile == '100', - 'Legacy avc1 parsing code out of sync with regex!'); + 'Legacy avc1 parsing code out of sync with regex!'); newCodecString += '6400'; } // Convert the level to hex and append to the codec string. const level = Number(match[2]); goog.asserts.assert(level < 256, - 'Invalid legacy avc1 level number!'); + 'Invalid legacy avc1 level number!'); newCodecString += (level >> 4).toString(16); newCodecString += (level & 0xf).toString(16); @@ -171,9 +171,9 @@ shaka.media.Transmuxer.prototype.transmux = function(data) { // Treat it as a transmuxing failure and reject the promise. if (this.isTransmuxing_) { this.transmuxPromise_.reject(new shaka.util.Error( - shaka.util.Error.Severity.CRITICAL, - shaka.util.Error.Category.MEDIA, - shaka.util.Error.Code.TRANSMUXING_FAILED)); + shaka.util.Error.Severity.CRITICAL, + shaka.util.Error.Category.MEDIA, + shaka.util.Error.Code.TRANSMUXING_FAILED)); } return this.transmuxPromise_; }; diff --git a/lib/net/http_fetch_plugin.js b/lib/net/http_fetch_plugin.js index 9e5133f0b..c3d9b09d0 100644 --- a/lib/net/http_fetch_plugin.js +++ b/lib/net/http_fetch_plugin.js @@ -159,7 +159,7 @@ shaka.net.HttpFetchPlugin.request_ = async function( if (readObj.done) { goog.asserts.assert(!readObj.value, - 'readObj should be unset when "done" is true.'); + 'readObj should be unset when "done" is true.'); controller.close(); } else { controller.enqueue(readObj.value); diff --git a/lib/net/http_plugin_utils.js b/lib/net/http_plugin_utils.js index fec6d56e0..13c26b22d 100644 --- a/lib/net/http_plugin_utils.js +++ b/lib/net/http_plugin_utils.js @@ -40,38 +40,38 @@ goog.require('shaka.util.StringUtils'); */ shaka.net.HttpPluginUtils.makeResponse = function(headers, data, status, uri, responseURL, requestType) { - if (status >= 200 && status <= 299 && status != 202) { - // Most 2xx HTTP codes are success cases. - if (responseURL) { - uri = responseURL; - } - /** @type {shaka.extern.Response} */ - const response = { - uri: uri, - data: data, - headers: headers, - fromCache: !!headers['x-shaka-from-cache'], - }; - return response; - } else { - let responseText = null; - try { - responseText = shaka.util.StringUtils.fromBytesAutoDetect(data); - } catch (exception) {} - shaka.log.debug('HTTP error text:', responseText); + if (status >= 200 && status <= 299 && status != 202) { + // Most 2xx HTTP codes are success cases. + if (responseURL) { + uri = responseURL; + } + /** @type {shaka.extern.Response} */ + const response = { + uri: uri, + data: data, + headers: headers, + fromCache: !!headers['x-shaka-from-cache'], + }; + return response; + } else { + let responseText = null; + try { + responseText = shaka.util.StringUtils.fromBytesAutoDetect(data); + } catch (exception) {} + shaka.log.debug('HTTP error text:', responseText); - const severity = status == 401 || status == 403 ? + const severity = status == 401 || status == 403 ? shaka.util.Error.Severity.CRITICAL : shaka.util.Error.Severity.RECOVERABLE; - throw new shaka.util.Error( - severity, - shaka.util.Error.Category.NETWORK, - shaka.util.Error.Code.BAD_HTTP_STATUS, - uri, - status, - responseText, - headers, - requestType); - } -}; + throw new shaka.util.Error( + severity, + shaka.util.Error.Category.NETWORK, + shaka.util.Error.Code.BAD_HTTP_STATUS, + uri, + status, + responseText, + headers, + requestType); + } + }; diff --git a/lib/net/http_xhr_plugin.js b/lib/net/http_xhr_plugin.js index 6c6b668da..b016e7e29 100644 --- a/lib/net/http_xhr_plugin.js +++ b/lib/net/http_xhr_plugin.js @@ -71,8 +71,8 @@ shaka.net.HttpXHRPlugin = function(uri, request, requestType, progressUpdated) { try { const response = shaka.net.HttpPluginUtils.makeResponse(headers, - target.response, target.status, uri, target.responseURL, - requestType); + target.response, target.status, uri, target.responseURL, + requestType); resolve(response); } catch (error) { goog.asserts.assert(error instanceof shaka.util.Error, @@ -102,7 +102,7 @@ shaka.net.HttpXHRPlugin = function(uri, request, requestType, progressUpdated) { if (currentTime - lastTime > 100 || (event.lengthComputable && event.loaded == event.total)) { progressUpdated(currentTime - lastTime, event.loaded - lastLoaded, - event.total - event.loaded); + event.total - event.loaded); lastLoaded = event.loaded; lastTime = currentTime; } @@ -118,11 +118,11 @@ shaka.net.HttpXHRPlugin = function(uri, request, requestType, progressUpdated) { })); return new shaka.util.AbortableOperation( - promise, - () => { - xhr.abort(); - return Promise.resolve(); - }); + promise, + () => { + xhr.abort(); + return Promise.resolve(); + }); }; diff --git a/lib/net/networking_engine.js b/lib/net/networking_engine.js index eda202b86..3346de9bd 100644 --- a/lib/net/networking_engine.js +++ b/lib/net/networking_engine.js @@ -161,18 +161,18 @@ shaka.net.NetworkingEngine.ResponseAndGotProgress; */ shaka.net.NetworkingEngine.registerScheme = function(scheme, plugin, priority) { - goog.asserts.assert(priority == undefined || priority > 0, - 'explicit priority must be > 0'); - priority = + goog.asserts.assert(priority == undefined || priority > 0, + 'explicit priority must be > 0'); + priority = priority || shaka.net.NetworkingEngine.PluginPriority.APPLICATION; - const existing = shaka.net.NetworkingEngine.schemes_[scheme]; - if (!existing || priority >= existing.priority) { - shaka.net.NetworkingEngine.schemes_[scheme] = { - priority: priority, - plugin: plugin, + const existing = shaka.net.NetworkingEngine.schemes_[scheme]; + if (!existing || priority >= existing.priority) { + shaka.net.NetworkingEngine.schemes_[scheme] = { + priority: priority, + plugin: plugin, + }; + } }; - } -}; /** @@ -206,8 +206,8 @@ shaka.net.NetworkingEngine.prototype.registerRequestFilter = function(filter) { */ shaka.net.NetworkingEngine.prototype.unregisterRequestFilter = function(filter) { - this.requestFilters_.delete(filter); -}; + this.requestFilters_.delete(filter); + }; /** @@ -240,8 +240,8 @@ shaka.net.NetworkingEngine.prototype.registerResponseFilter = function(filter) { */ shaka.net.NetworkingEngine.prototype.unregisterResponseFilter = function(filter) { - this.responseFilters_.delete(filter); -}; + this.responseFilters_.delete(filter); + }; /** @@ -325,7 +325,7 @@ shaka.net.NetworkingEngine.prototype.request = function(type, request) { } goog.asserts.assert(request.uris && request.uris.length, - 'Request without URIs!'); + 'Request without URIs!'); // If a request comes from outside the library, some parameters may be left // undefined. To make it easier for application developers, we will fill them @@ -346,7 +346,7 @@ shaka.net.NetworkingEngine.prototype.request = function(type, request) { () => this.makeRequestWithRetry_(type, request, numBytesRemainingObj)); const responseFilterOperation = requestOperation.chain( (responseAndGotProgress) => - this.filterResponse_(type, responseAndGotProgress)); + this.filterResponse_(type, responseAndGotProgress)); // Keep track of time spent in filters. const requestFilterStartTime = Date.now(); @@ -388,7 +388,7 @@ shaka.net.NetworkingEngine.prototype.request = function(type, request) { // Add the operation to the manager for later cleanup. const pendingRequest = new shaka.net.NetworkingEngine.PendingRequest(operation.promise, - operation.onAbort_, numBytesRemainingObj); + operation.onAbort_, numBytesRemainingObj); this.operationManager_.manage(pendingRequest); return pendingRequest; }; @@ -436,12 +436,12 @@ shaka.net.NetworkingEngine.prototype.filterRequest_ = function(type, request) { */ shaka.net.NetworkingEngine.prototype.makeRequestWithRetry_ = function(type, request, numBytesRemainingObj) { - const backoff = new shaka.net.Backoff( - request.retryParameters, /* autoReset */ false); - const index = 0; - return this.send_(type, request, backoff, index, /* lastError */ null, - numBytesRemainingObj); -}; + const backoff = new shaka.net.Backoff( + request.retryParameters, /* autoReset */ false); + const index = 0; + return this.send_(type, request, backoff, index, /* lastError */ null, + numBytesRemainingObj); + }; /** @@ -468,7 +468,7 @@ shaka.net.NetworkingEngine.prototype.send_ = function( // If there is no scheme, infer one from the location. scheme = shaka.net.NetworkingEngine.getLocationProtocol_(); goog.asserts.assert(scheme[scheme.length - 1] == ':', - 'location.protocol expected to end with a colon!'); + 'location.protocol expected to end with a colon!'); // Drop the colon. scheme = scheme.slice(0, -1); @@ -504,15 +504,15 @@ shaka.net.NetworkingEngine.prototype.send_ = function( const segment = shaka.net.NetworkingEngine.RequestType.SEGMENT; return plugin(request.uris[index], - request, - type, - // The following function is passed to plugin. - (time, bytes, numBytesRemaining) => { - if (this.onProgressUpdated_ && type == segment) { - this.onProgressUpdated_(time, bytes); - gotProgress = true; - numBytesRemainingObj.setBytes(numBytesRemaining); - } + request, + type, + // The following function is passed to plugin. + (time, bytes, numBytesRemaining) => { + if (this.onProgressUpdated_ && type == segment) { + this.onProgressUpdated_(time, bytes); + gotProgress = true; + numBytesRemainingObj.setBytes(numBytesRemaining); + } }); }).chain((response) => { if (response.timeMs == undefined) { @@ -548,7 +548,7 @@ shaka.net.NetworkingEngine.prototype.send_ = function( index = (index + 1) % request.uris.length; const shakaError = /** @type {shaka.util.Error} */(error); return this.send_(type, request, backoff, index, shakaError, - numBytesRemainingObj); + numBytesRemainingObj); } // The error was not recoverable, so do not try again. @@ -569,36 +569,36 @@ shaka.net.NetworkingEngine.prototype.send_ = function( */ shaka.net.NetworkingEngine.prototype.filterResponse_ = function(type, responseAndGotProgress) { - let filterOperation = shaka.util.AbortableOperation.completed(undefined); - for (const responseFilter of this.responseFilters_) { - // Response filters are run sequentially. - filterOperation = filterOperation.chain( - responseFilter.bind(null, type, responseAndGotProgress.response)); - } - // If successful, return the filtered response with whether it got progress. - return filterOperation.chain(() => { - return responseAndGotProgress; - }, (e) => { - // Catch any errors thrown by request filters, and substitute - // them with a Shaka-native error. + let filterOperation = shaka.util.AbortableOperation.completed(undefined); + for (const responseFilter of this.responseFilters_) { + // Response filters are run sequentially. + filterOperation = filterOperation.chain( + responseFilter.bind(null, type, responseAndGotProgress.response)); + } + // If successful, return the filtered response with whether it got progress. + return filterOperation.chain(() => { + return responseAndGotProgress; + }, (e) => { + // Catch any errors thrown by request filters, and substitute + // them with a Shaka-native error. - if (e && e.code == shaka.util.Error.Code.OPERATION_ABORTED) { - // Don't change anything if the operation was aborted. - throw e; - } + if (e && e.code == shaka.util.Error.Code.OPERATION_ABORTED) { + // Don't change anything if the operation was aborted. + throw e; + } - // The error is assumed to be critical if the original wasn't a Shaka error. - let severity = shaka.util.Error.Severity.CRITICAL; - if (e instanceof shaka.util.Error) { - severity = e.severity; - } + // The error is assumed to be critical if the original wasn't a Shaka error. + let severity = shaka.util.Error.Severity.CRITICAL; + if (e instanceof shaka.util.Error) { + severity = e.severity; + } - throw new shaka.util.Error( - severity, - shaka.util.Error.Category.NETWORK, - shaka.util.Error.Code.RESPONSE_FILTER_ERROR, e); - }); -}; + throw new shaka.util.Error( + severity, + shaka.util.Error.Category.NETWORK, + shaka.util.Error.Code.RESPONSE_FILTER_ERROR, e); + }); + }; /** @@ -655,7 +655,7 @@ shaka.net.NetworkingEngine.NumBytesRemainingClass = class { */ shaka.net.NetworkingEngine.PendingRequest = class extends shaka.util.AbortableOperation { - /** + /** * @param {!Promise} promise * A Promise which represents the underlying operation. It is resolved when * the operation is complete, and rejected if the operation fails or is @@ -670,17 +670,17 @@ shaka.net.NetworkingEngine.PendingRequest = * @param {shaka.net.NetworkingEngine.NumBytesRemainingClass} * numBytesRemainingObj */ - constructor(promise, onAbort, numBytesRemainingObj) { - super(promise, onAbort); + constructor(promise, onAbort, numBytesRemainingObj) { + super(promise, onAbort); - /** @private {shaka.net.NetworkingEngine.NumBytesRemainingClass} */ - this.bytesRemaining_ = numBytesRemainingObj; - } + /** @private {shaka.net.NetworkingEngine.NumBytesRemainingClass} */ + this.bytesRemaining_ = numBytesRemainingObj; + } - /** + /** * @return {number} */ - getBytesRemaining() { - return this.bytesRemaining_.getBytes(); - } -}; + getBytesRemaining() { + return this.bytesRemaining_.getBytes(); + } + }; diff --git a/lib/offline/indexeddb/v1_storage_cell.js b/lib/offline/indexeddb/v1_storage_cell.js index ef95b2d42..26958985d 100644 --- a/lib/offline/indexeddb/v1_storage_cell.js +++ b/lib/offline/indexeddb/v1_storage_cell.js @@ -176,10 +176,10 @@ shaka.offline.indexeddb.V1StorageCell = class { */ rejectAdd_(storeName) { return Promise.reject(new shaka.util.Error( - shaka.util.Error.Severity.CRITICAL, - shaka.util.Error.Category.STORAGE, - shaka.util.Error.Code.NEW_KEY_OPERATION_NOT_SUPPORTED, - 'Cannot add new value to ' + storeName)); + shaka.util.Error.Severity.CRITICAL, + shaka.util.Error.Category.STORAGE, + shaka.util.Error.Code.NEW_KEY_OPERATION_NOT_SUPPORTED, + 'Cannot add new value to ' + storeName)); } /** @@ -313,11 +313,11 @@ shaka.offline.indexeddb.V1StorageCell = class { // } goog.asserts.assert( - old.startTime != null, - 'Old period format should have a start time field'); + old.startTime != null, + 'Old period format should have a start time field'); goog.asserts.assert( - old.streams != null, - 'Old period format should have a streams field'); + old.streams != null, + 'Old period format should have a streams field'); // In the case that this is really old (like really old, like dinosaurs // roaming the Earth old) there may be no variants, so we need to add those. diff --git a/lib/offline/indexeddb/v2_storage_cell.js b/lib/offline/indexeddb/v2_storage_cell.js index b67b67795..dabdae1b9 100644 --- a/lib/offline/indexeddb/v2_storage_cell.js +++ b/lib/offline/indexeddb/v2_storage_cell.js @@ -36,9 +36,9 @@ shaka.offline.indexeddb.V2StorageCell = class { * @param {boolean} isFixedKey */ constructor(connection, - segmentStore, - manifestStore, - isFixedKey) { + segmentStore, + manifestStore, + isFixedKey) { /** @private {!shaka.offline.indexeddb.DBConnection} */ this.connection_ = new shaka.offline.indexeddb.DBConnection(connection); @@ -143,10 +143,10 @@ shaka.offline.indexeddb.V2StorageCell = class { // reject the request immediately instead of allowing it to try. if (this.isFixedKey_) { return Promise.reject(new shaka.util.Error( - shaka.util.Error.Severity.RECOVERABLE, - shaka.util.Error.Category.STORAGE, - shaka.util.Error.Code.NEW_KEY_OPERATION_NOT_SUPPORTED, - 'Cannot add new value to ' + storeName)); + shaka.util.Error.Severity.RECOVERABLE, + shaka.util.Error.Category.STORAGE, + shaka.util.Error.Code.NEW_KEY_OPERATION_NOT_SUPPORTED, + 'Cannot add new value to ' + storeName)); } const op = this.connection_.startReadWriteOperation(storeName); diff --git a/lib/offline/manifest_converter.js b/lib/offline/manifest_converter.js index aa6154acb..87a0d5c62 100644 --- a/lib/offline/manifest_converter.js +++ b/lib/offline/manifest_converter.js @@ -58,7 +58,7 @@ shaka.offline.ManifestConverter = class { timeline.setDuration(manifestDB.duration); const periods = manifestDB.periods.map((period) => - this.fromPeriodDB(period, timeline)); + this.fromPeriodDB(period, timeline)); const drmInfos = manifestDB.drmInfo ? [manifestDB.drmInfo] : []; if (manifestDB.drmInfo) { @@ -188,7 +188,7 @@ shaka.offline.ManifestConverter = class { fromStreamDB_(streamDB) { /** @type {!Array.<!shaka.media.SegmentReference>} */ const segments = streamDB.segments.map((segment, index) => - this.fromSegmentDB_(index, segment)); + this.fromSegmentDB_(index, segment)); /** @type {!shaka.media.SegmentIndex} */ const segmentIndex = new shaka.media.SegmentIndex(segments); diff --git a/lib/offline/offline_manifest_parser.js b/lib/offline/offline_manifest_parser.js index 720b44b89..b16e3bfa5 100644 --- a/lib/offline/offline_manifest_parser.js +++ b/lib/offline/offline_manifest_parser.js @@ -47,37 +47,37 @@ shaka.offline.OfflineManifestParser.prototype.configure = function(config) { /** @override */ shaka.offline.OfflineManifestParser.prototype.start = async function(uriString, playerInterface) { - /** @type {shaka.offline.OfflineUri} */ - const uri = shaka.offline.OfflineUri.parse(uriString); - this.uri_ = uri; + /** @type {shaka.offline.OfflineUri} */ + const uri = shaka.offline.OfflineUri.parse(uriString); + this.uri_ = uri; - if (uri == null || !uri.isManifest()) { - return Promise.reject(new shaka.util.Error( - shaka.util.Error.Severity.CRITICAL, - shaka.util.Error.Category.NETWORK, - shaka.util.Error.Code.MALFORMED_OFFLINE_URI, - uri)); - } + if (uri == null || !uri.isManifest()) { + return Promise.reject(new shaka.util.Error( + shaka.util.Error.Severity.CRITICAL, + shaka.util.Error.Category.NETWORK, + shaka.util.Error.Code.MALFORMED_OFFLINE_URI, + uri)); + } - /** @type {!shaka.offline.StorageMuxer} */ - const muxer = new shaka.offline.StorageMuxer(); + /** @type {!shaka.offline.StorageMuxer} */ + const muxer = new shaka.offline.StorageMuxer(); - try { - await muxer.init(); + try { + await muxer.init(); - const cell = await muxer.getCell(uri.mechanism(), uri.cell()); + const cell = await muxer.getCell(uri.mechanism(), uri.cell()); - const manifests = await cell.getManifests([uri.key()]); - const manifest = manifests[0]; + const manifests = await cell.getManifests([uri.key()]); + const manifest = manifests[0]; - const converter = new shaka.offline.ManifestConverter( - uri.mechanism(), uri.cell()); + const converter = new shaka.offline.ManifestConverter( + uri.mechanism(), uri.cell()); - return converter.fromManifestDB(manifest); - } finally { - await muxer.destroy(); - } -}; + return converter.fromManifestDB(manifest); + } finally { + await muxer.destroy(); + } + }; /** @override */ @@ -95,38 +95,38 @@ shaka.offline.OfflineManifestParser.prototype.update = function() { /** @override */ shaka.offline.OfflineManifestParser.prototype.onExpirationUpdated = async function(sessionId, expiration) { - goog.asserts.assert( - this.uri_, 'Should not get update event before start has been called'); + goog.asserts.assert( + this.uri_, 'Should not get update event before start has been called'); - /** @type {!shaka.offline.OfflineUri} */ - const uri = this.uri_; + /** @type {!shaka.offline.OfflineUri} */ + const uri = this.uri_; - /** @type {!shaka.offline.StorageMuxer} */ - const muxer = new shaka.offline.StorageMuxer(); + /** @type {!shaka.offline.StorageMuxer} */ + const muxer = new shaka.offline.StorageMuxer(); - try { - await muxer.init(); + try { + await muxer.init(); - const cell = await muxer.getCell(uri.mechanism(), uri.cell()); + const cell = await muxer.getCell(uri.mechanism(), uri.cell()); - const manifests = await cell.getManifests([uri.key()]); - const manifest = manifests[0]; + const manifests = await cell.getManifests([uri.key()]); + const manifest = manifests[0]; - const foundSession = manifest.sessionIds.includes(sessionId); - const newExpiration = manifest.expiration == undefined || + const foundSession = manifest.sessionIds.includes(sessionId); + const newExpiration = manifest.expiration == undefined || manifest.expiration > expiration; - if (foundSession && newExpiration) { - shaka.log.debug('Updating expiration for stored content'); - await cell.updateManifestExpiration(uri.key(), expiration); - } - } catch (e) { - // Ignore errors with update. - shaka.log.error('There was an error updating', uri, e); - } finally { - await muxer.destroy(); - } -}; + if (foundSession && newExpiration) { + shaka.log.debug('Updating expiration for stored content'); + await cell.updateManifestExpiration(uri.key(), expiration); + } + } catch (e) { + // Ignore errors with update. + shaka.log.error('There was an error updating', uri, e); + } finally { + await muxer.destroy(); + } + }; shaka.media.ManifestParser.registerParserByMime( diff --git a/lib/offline/session_deleter.js b/lib/offline/session_deleter.js index eeefdc90c..800c4bc1b 100644 --- a/lib/offline/session_deleter.js +++ b/lib/offline/session_deleter.js @@ -150,7 +150,7 @@ shaka.offline.SessionDeleter = class { // TODO: Add a way to change the license server in DrmEngine to avoid // resetting EME for different license servers. const comp = (x, y) => - x.robustness == y.robustness && x.contentType == y.contentType; + x.robustness == y.robustness && x.contentType == y.contentType; return a.keySystem == b.keySystem && a.licenseUri == b.licenseUri && ArrayUtils.hasSameElements( a.audioCapabilities, b.audioCapabilities, comp) && diff --git a/lib/offline/storage.js b/lib/offline/storage.js index 9e7b70a11..de3584997 100644 --- a/lib/offline/storage.js +++ b/lib/offline/storage.js @@ -192,7 +192,7 @@ shaka.offline.Storage.prototype.destroy = function() { */ shaka.offline.Storage.prototype.configure = function(config, value) { goog.asserts.assert(typeof(config) == 'object' || arguments.length == 2, - 'String configs should have values!'); + 'String configs should have values!'); // ('fieldName', value) format if (arguments.length == 2 && typeof(config) == 'string') { @@ -268,13 +268,13 @@ shaka.offline.Storage.prototype.getNetworkingEngine = function() { shaka.offline.Storage.prototype.store = function(uri, appMetadata, mimeType) { const getParser = async () => { if (mimeType && typeof mimeType != 'string') { - shaka.Deprecate.deprecateFeature( - 2, 6, - 'Storing with a manifest parser factory', - 'Please register a manifest parser and for the mime-type.'); + shaka.Deprecate.deprecateFeature( + 2, 6, + 'Storing with a manifest parser factory', + 'Please register a manifest parser and for the mime-type.'); const Factory = - /** @type {shaka.extern.ManifestParser.Factory} */(mimeType); + /** @type {shaka.extern.ManifestParser.Factory} */(mimeType); return new Factory(); } diff --git a/lib/player.js b/lib/player.js index 9f127b304..13932b1dd 100644 --- a/lib/player.js +++ b/lib/player.js @@ -385,17 +385,17 @@ shaka.Player.prototype.destroy = async function() { }; events.onCancel = () => { goog.asserts.assert(false, - 'Our final detach call should never be cancelled.'); + 'Our final detach call should never be cancelled.'); resolve(); }; events.onError = () => { goog.asserts.assert(false, - 'Our final detach call should never see an error'); + 'Our final detach call should never see an error'); resolve(); }; events.onSkip = () => { goog.asserts.assert(false, - 'Our final detach call should never be skipped'); + 'Our final detach call should never be skipped'); resolve(); }; }); @@ -741,7 +741,7 @@ shaka.Player.isBrowserSupported = function() { */ shaka.Player.probeSupport = function() { goog.asserts.assert(shaka.Player.isBrowserSupported(), - 'Must have basic support'); + 'Must have basic support'); return shaka.media.DrmEngine.probeSupport().then((drm) => { const manifest = shaka.media.ManifestParser.probeSupport(); const media = shaka.media.MediaSourceEngine.probeSupport(); @@ -777,7 +777,7 @@ shaka.Player.probeSupport = function() { * @export */ shaka.Player.prototype.attach = function(mediaElement, - initializeMediaSource = true) { + initializeMediaSource = true) { // Do not allow the player to be used after |destroy| is called. if (this.loadMode_ == shaka.Player.LoadMode.DESTROYED) { return Promise.reject(this.createAbortLoadError_()); @@ -962,7 +962,7 @@ shaka.Player.prototype.load = function(assetUri, startTime, mimeType) { 'Loading with a manifest parser factory', 'Please register a manifest parser and for the mime-type.'); const Factory = - /** @type {shaka.extern.ManifestParser.Factory} */ (mimeType); + /** @type {shaka.extern.ManifestParser.Factory} */ (mimeType); payload.factory = () => new Factory(); } @@ -1092,7 +1092,7 @@ shaka.Player.prototype.shouldUseSrcEquals_ = function(payload) { // If we land here, both are feasible. goog.asserts.assert(canPlayNatively && canPlayMediaSource, - 'Both native and MSE playback should be possible!'); + 'Both native and MSE playback should be possible!'); // We would prefer MediaSource in some cases, and src= in others. For // example, Android has native HLS, but we'd prefer our own MediaSource @@ -1386,7 +1386,7 @@ shaka.Player.prototype.onInitializeParser_ = async function(has, wants) { this.networkingEngine_, 'Need networking engine when initializing the parser.'); goog.asserts.assert( - this.config_, + this.config_, 'Need player config when initializing the parser.'); // We are going to "lock-in" the factory, mime type, and uri since they are @@ -1456,7 +1456,7 @@ shaka.Player.prototype.onParseManifest_ = function(has, wants) { this.networkingEngine_, 'Need networking engine to parse manifest.'); goog.asserts.assert( - this.config_, + this.config_, 'Need player config to parse manifest.'); goog.asserts.assert( @@ -1658,8 +1658,8 @@ shaka.Player.prototype.onLoad_ = async function(has, wants) { this.currentTextLanguage_ = this.config_.preferredTextLanguage; shaka.Player.applyPlayRange_(this.manifest_.presentationTimeline, - this.config_.playRangeStart, - this.config_.playRangeEnd); + this.config_.playRangeStart, + this.config_.playRangeEnd); await this.drmEngine_.attach(mediaElement); @@ -2202,7 +2202,7 @@ shaka.Player.prototype.startBufferManagement_ = function(rebufferingGoal) { Math.min(shaka.Player.TYPICAL_BUFFERING_THRESHOLD_, rebufferingGoal / 2); this.bufferObserver_ = new shaka.media.BufferingObserver( - starvingThreshold, satisfiedThreshold); + starvingThreshold, satisfiedThreshold); // Force us back to a buffering state. This ensure everything is starting in // the same state. @@ -2326,7 +2326,7 @@ shaka.Player.prototype.createStreamingEngine = function() { shaka.Player.prototype.configure = function(config, value) { goog.asserts.assert(this.config_, 'Config must not be null!'); goog.asserts.assert(typeof(config) == 'object' || arguments.length == 2, - 'String configs should have values!'); + 'String configs should have values!'); // ('fieldName', value) format if (arguments.length == 2 && typeof(config) == 'string') { @@ -2505,7 +2505,7 @@ shaka.Player.prototype.getAssetUri = function() { */ shaka.Player.prototype.getManifestUri = function() { shaka.Deprecate.deprecateFeature( - 2, 6, 'getManifestUri', 'Please use "getAssetUri" instead.'); + 2, 6, 'getManifestUri', 'Please use "getAssetUri" instead.'); return this.getAssetUri(); }; @@ -2787,7 +2787,7 @@ shaka.Player.prototype.getVariantTracks = function() { // to generate a variant list that is usable for changing languages. const audioTracks = Array.from(this.video_.audioTracks); return audioTracks.map((audio) => - shaka.util.StreamUtils.html5AudioTrackToTrack(audio)); + shaka.util.StreamUtils.html5AudioTrackToTrack(audio)); } else { return []; } @@ -2985,7 +2985,7 @@ shaka.Player.prototype.selectVariantTrack = function( // Add entries to the history. this.addVariantToSwitchHistory_(period, variant, - /* fromAdaptation= */ false); + /* fromAdaptation= */ false); this.switchVariant_(variant, clearBuffer, safeMargin); // Workaround for https://github.com/google/shaka-player/issues/1299 @@ -3783,18 +3783,18 @@ shaka.Player.prototype.filterNewPeriod_ = function(period) { */ shaka.Player.prototype.switchVariant_ = function(variant, clearBuffer = false, safeMargin = 0) { - if (this.switchingPeriods_) { - // Store this action for later. - this.deferredVariant_ = variant; - this.deferredVariantClearBuffer_ = clearBuffer; - this.deferredVariantClearBufferSafeMargin_ = safeMargin; - } else { - // Act now. - this.streamingEngine_.switchVariant(variant, clearBuffer, safeMargin); - // Dispatch a 'variantchanged' event - this.onVariantChanged_(); - } -}; + if (this.switchingPeriods_) { + // Store this action for later. + this.deferredVariant_ = variant; + this.deferredVariantClearBuffer_ = clearBuffer; + this.deferredVariantClearBufferSafeMargin_ = safeMargin; + } else { + // Act now. + this.streamingEngine_.switchVariant(variant, clearBuffer, safeMargin); + // Dispatch a 'variantchanged' event + this.onVariantChanged_(); + } + }; /** @@ -4107,7 +4107,7 @@ shaka.Player.prototype.chooseStreamsAndSwitch_ = function(period) { const chosenText = this.chooseTextStream_(period.textStreams); if (chosenText && this.shouldStreamText_()) { this.addTextStreamToSwitchHistory_( - period, chosenText, /* fromAdaptation= */ true); + period, chosenText, /* fromAdaptation= */ true); this.switchTextStream_(chosenText); } @@ -4631,8 +4631,8 @@ shaka.Player.prototype.shouldStreamText_ = function() { * @private */ shaka.Player.applyPlayRange_ = function(timeline, - playRangeStart, - playRangeEnd) { + playRangeStart, + playRangeEnd) { if (playRangeStart > 0) { if (timeline.isLive()) { shaka.log.warning( @@ -5302,7 +5302,7 @@ shaka.Player.prototype.getNextAfterUnload_ = function(goingTo, has, wants) { * @private */ shaka.Player.prototype.getNextMatchingAllDependencies_ = function( - destinationNode, nextNode, resetNode, goingTo, has, wants) { + destinationNode, nextNode, resetNode, goingTo, has, wants) { if (goingTo == destinationNode && has.mediaElement == wants.mediaElement && has.uri == wants.uri && diff --git a/lib/polyfill/input_event.js b/lib/polyfill/input_event.js index 19c538cbc..dd26b2801 100644 --- a/lib/polyfill/input_event.js +++ b/lib/polyfill/input_event.js @@ -77,21 +77,21 @@ shaka.polyfill.InputEvent.originalAddEventListener_; */ shaka.polyfill.InputEvent.addEventListener_ = function(type, listener, options) { - if (type == 'input') { - // Based on the type of input element, translate the HTML5 'input' event to - // one that IE11 will actually dispatch. + if (type == 'input') { + // Based on the type of input element, translate the HTML5 'input' event to + // one that IE11 will actually dispatch. - switch (this.type) { - // For range inputs, we use the 'change' event. - case 'range': - type = 'change'; - break; - } - } + switch (this.type) { + // For range inputs, we use the 'change' event. + case 'range': + type = 'change'; + break; + } + } - shaka.polyfill.InputEvent.originalAddEventListener_.call( - this, type, listener, options); -}; + shaka.polyfill.InputEvent.originalAddEventListener_.call( + this, type, listener, options); + }; shaka.polyfill.register(shaka.polyfill.InputEvent.install); diff --git a/lib/polyfill/patchedmediakeys_apple.js b/lib/polyfill/patchedmediakeys_apple.js index 183cfeb7a..ed11231a2 100644 --- a/lib/polyfill/patchedmediakeys_apple.js +++ b/lib/polyfill/patchedmediakeys_apple.js @@ -92,20 +92,20 @@ shaka.polyfill.PatchedMediaKeysApple.install = function() { */ shaka.polyfill.PatchedMediaKeysApple.requestMediaKeySystemAccess = function(keySystem, supportedConfigurations) { - shaka.log.debug('PatchedMediaKeysApple.requestMediaKeySystemAccess'); - goog.asserts.assert(this == navigator, - 'bad "this" for requestMediaKeySystemAccess'); + shaka.log.debug('PatchedMediaKeysApple.requestMediaKeySystemAccess'); + goog.asserts.assert(this == navigator, + 'bad "this" for requestMediaKeySystemAccess'); - // Alias. - const PatchedMediaKeysApple = shaka.polyfill.PatchedMediaKeysApple; - try { - const access = new PatchedMediaKeysApple.MediaKeySystemAccess( - keySystem, supportedConfigurations); - return Promise.resolve(/** @type {!MediaKeySystemAccess} */ (access)); - } catch (exception) { - return Promise.reject(exception); - } -}; + // Alias. + const PatchedMediaKeysApple = shaka.polyfill.PatchedMediaKeysApple; + try { + const access = new PatchedMediaKeysApple.MediaKeySystemAccess( + keySystem, supportedConfigurations); + return Promise.resolve(/** @type {!MediaKeySystemAccess} */ (access)); + } catch (exception) { + return Promise.reject(exception); + } + }; /** @@ -120,35 +120,35 @@ shaka.polyfill.PatchedMediaKeysApple.requestMediaKeySystemAccess = */ shaka.polyfill.PatchedMediaKeysApple.MediaKeySystemAccess = function(keySystem, supportedConfigurations) { - shaka.log.debug('PatchedMediaKeysApple.MediaKeySystemAccess'); + shaka.log.debug('PatchedMediaKeysApple.MediaKeySystemAccess'); - /** @type {string} */ - this.keySystem = keySystem; + /** @type {string} */ + this.keySystem = keySystem; - /** @private {!MediaKeySystemConfiguration} */ - this.configuration_; + /** @private {!MediaKeySystemConfiguration} */ + this.configuration_; - // Optimization: WebKitMediaKeys.isTypeSupported delays responses by a - // significant amount of time, possibly to discourage fingerprinting. - // Since we know only FairPlay is supported here, let's skip queries for - // anything else to speed up the process. - if (keySystem.startsWith('com.apple.fps')) { - for (const cfg of supportedConfigurations) { - const newCfg = this.checkConfig_(cfg); - if (newCfg) { - this.configuration_ = newCfg; - return; + // Optimization: WebKitMediaKeys.isTypeSupported delays responses by a + // significant amount of time, possibly to discourage fingerprinting. + // Since we know only FairPlay is supported here, let's skip queries for + // anything else to speed up the process. + if (keySystem.startsWith('com.apple.fps')) { + for (const cfg of supportedConfigurations) { + const newCfg = this.checkConfig_(cfg); + if (newCfg) { + this.configuration_ = newCfg; + return; + } + } } - } - } - // As per the spec, this should be a DOMException, but there is not a public - // constructor for DOMException. - const unsupportedKeySystemError = new Error('Unsupported keySystem'); - unsupportedKeySystemError.name = 'NotSupportedError'; - unsupportedKeySystemError.code = DOMException.NOT_SUPPORTED_ERR; - throw unsupportedKeySystemError; -}; + // As per the spec, this should be a DOMException, but there is not a public + // constructor for DOMException. + const unsupportedKeySystemError = new Error('Unsupported keySystem'); + unsupportedKeySystemError.name = 'NotSupportedError'; + unsupportedKeySystemError.code = DOMException.NOT_SUPPORTED_ERR; + throw unsupportedKeySystemError; + }; /** @@ -161,95 +161,95 @@ shaka.polyfill.PatchedMediaKeysApple.MediaKeySystemAccess = */ shaka.polyfill.PatchedMediaKeysApple.MediaKeySystemAccess.prototype .checkConfig_ = function(cfg) { - if (cfg.persistentState == 'required') { - // Not supported by the prefixed API. - return null; - } + if (cfg.persistentState == 'required') { + // Not supported by the prefixed API. + return null; + } - // Create a new config object and start adding in the pieces which we find - // support for. We will return this from getConfiguration() later if asked. + // Create a new config object and start adding in the pieces which we find + // support for. We will return this from getConfiguration() later if asked. - /** @type {!MediaKeySystemConfiguration} */ - const newCfg = { - 'audioCapabilities': [], - 'videoCapabilities': [], - // It is technically against spec to return these as optional, but we - // don't truly know their values from the prefixed API: - 'persistentState': 'optional', - 'distinctiveIdentifier': 'optional', - // Pretend the requested init data types are supported, since we don't - // really know that either: - 'initDataTypes': cfg.initDataTypes, - 'sessionTypes': ['temporary'], - 'label': cfg.label, - }; + /** @type {!MediaKeySystemConfiguration} */ + const newCfg = { + 'audioCapabilities': [], + 'videoCapabilities': [], + // It is technically against spec to return these as optional, but we + // don't truly know their values from the prefixed API: + 'persistentState': 'optional', + 'distinctiveIdentifier': 'optional', + // Pretend the requested init data types are supported, since we don't + // really know that either: + 'initDataTypes': cfg.initDataTypes, + 'sessionTypes': ['temporary'], + 'label': cfg.label, + }; - // PatchedMediaKeysApple tests for key system availability through - // WebKitMediaKeys.isTypeSupported. - let ranAnyTests = false; - let success = false; + // PatchedMediaKeysApple tests for key system availability through + // WebKitMediaKeys.isTypeSupported. + let ranAnyTests = false; + let success = false; - if (cfg.audioCapabilities) { - for (const cap of cfg.audioCapabilities) { - if (cap.contentType) { - ranAnyTests = true; + if (cfg.audioCapabilities) { + for (const cap of cfg.audioCapabilities) { + if (cap.contentType) { + ranAnyTests = true; - const contentType = cap.contentType.split(';')[0]; - if (WebKitMediaKeys.isTypeSupported(this.keySystem, contentType)) { - newCfg.audioCapabilities.push(cap); - success = true; + const contentType = cap.contentType.split(';')[0]; + if (WebKitMediaKeys.isTypeSupported(this.keySystem, contentType)) { + newCfg.audioCapabilities.push(cap); + success = true; + } + } } } - } - } - if (cfg.videoCapabilities) { - for (const cap of cfg.videoCapabilities) { - if (cap.contentType) { - ranAnyTests = true; + if (cfg.videoCapabilities) { + for (const cap of cfg.videoCapabilities) { + if (cap.contentType) { + ranAnyTests = true; - const contentType = cap.contentType.split(';')[0]; - if (WebKitMediaKeys.isTypeSupported(this.keySystem, contentType)) { - newCfg.videoCapabilities.push(cap); - success = true; + const contentType = cap.contentType.split(';')[0]; + if (WebKitMediaKeys.isTypeSupported(this.keySystem, contentType)) { + newCfg.videoCapabilities.push(cap); + success = true; + } + } } } - } - } - if (!ranAnyTests) { - // If no specific types were requested, we check all common types to find - // out if the key system is present at all. - success = WebKitMediaKeys.isTypeSupported(this.keySystem, 'video/mp4'); - } + if (!ranAnyTests) { + // If no specific types were requested, we check all common types to find + // out if the key system is present at all. + success = WebKitMediaKeys.isTypeSupported(this.keySystem, 'video/mp4'); + } - if (success) { - return newCfg; - } - return null; -}; + if (success) { + return newCfg; + } + return null; + }; /** @override */ shaka.polyfill.PatchedMediaKeysApple.MediaKeySystemAccess.prototype .createMediaKeys = function() { - shaka.log.debug('PatchedMediaKeysApple.MediaKeySystemAccess.createMediaKeys'); + shaka.log.debug('PatchedMediaKeysApple.MediaKeySystemAccess.createMediaKeys'); - // Alias - const PatchedMediaKeysApple = shaka.polyfill.PatchedMediaKeysApple; + // Alias + const PatchedMediaKeysApple = shaka.polyfill.PatchedMediaKeysApple; - const mediaKeys = new PatchedMediaKeysApple.MediaKeys(this.keySystem); - return Promise.resolve(/** @type {!MediaKeys} */ (mediaKeys)); -}; + const mediaKeys = new PatchedMediaKeysApple.MediaKeys(this.keySystem); + return Promise.resolve(/** @type {!MediaKeys} */ (mediaKeys)); + }; /** @override */ shaka.polyfill.PatchedMediaKeysApple.MediaKeySystemAccess.prototype .getConfiguration = function() { - shaka.log.debug( - 'PatchedMediaKeysApple.MediaKeySystemAccess.getConfiguration'); - return this.configuration_; -}; + shaka.log.debug( + 'PatchedMediaKeysApple.MediaKeySystemAccess.getConfiguration'); + return this.configuration_; + }; /** @@ -263,21 +263,21 @@ shaka.polyfill.PatchedMediaKeysApple.MediaKeySystemAccess.prototype shaka.polyfill.PatchedMediaKeysApple.setMediaKeys = function(mediaKeys) { shaka.log.debug('PatchedMediaKeysApple.setMediaKeys'); goog.asserts.assert(this instanceof HTMLMediaElement, - 'bad "this" for setMediaKeys'); + 'bad "this" for setMediaKeys'); // Alias const PatchedMediaKeysApple = shaka.polyfill.PatchedMediaKeysApple; const newMediaKeys = - /** @type {shaka.polyfill.PatchedMediaKeysApple.MediaKeys} */ ( + /** @type {shaka.polyfill.PatchedMediaKeysApple.MediaKeys} */ ( mediaKeys); const oldMediaKeys = - /** @type {shaka.polyfill.PatchedMediaKeysApple.MediaKeys} */ ( + /** @type {shaka.polyfill.PatchedMediaKeysApple.MediaKeys} */ ( this.mediaKeys); if (oldMediaKeys && oldMediaKeys != newMediaKeys) { goog.asserts.assert(oldMediaKeys instanceof PatchedMediaKeysApple.MediaKeys, - 'non-polyfill instance of oldMediaKeys'); + 'non-polyfill instance of oldMediaKeys'); // Have the old MediaKeys stop listening to events on the video tag. oldMediaKeys.setMedia(null); } @@ -287,7 +287,7 @@ shaka.polyfill.PatchedMediaKeysApple.setMediaKeys = function(mediaKeys) { if (newMediaKeys) { goog.asserts.assert(newMediaKeys instanceof PatchedMediaKeysApple.MediaKeys, - 'non-polyfill instance of newMediaKeys'); + 'non-polyfill instance of newMediaKeys'); return newMediaKeys.setMedia(this); } @@ -320,33 +320,33 @@ shaka.polyfill.PatchedMediaKeysApple.MediaKeys = function(keySystem) { /** @override */ shaka.polyfill.PatchedMediaKeysApple.MediaKeys.prototype .createSession = function(sessionType) { - shaka.log.debug('PatchedMediaKeysApple.MediaKeys.createSession'); + shaka.log.debug('PatchedMediaKeysApple.MediaKeys.createSession'); - sessionType = sessionType || 'temporary'; - // For now, only the 'temporary' type is supported. - if (sessionType != 'temporary') { - throw new TypeError('Session type ' + sessionType + + sessionType = sessionType || 'temporary'; + // For now, only the 'temporary' type is supported. + if (sessionType != 'temporary') { + throw new TypeError('Session type ' + sessionType + ' is unsupported on this platform.'); - } + } - // Alias - const PatchedMediaKeysApple = shaka.polyfill.PatchedMediaKeysApple; + // Alias + const PatchedMediaKeysApple = shaka.polyfill.PatchedMediaKeysApple; - return new PatchedMediaKeysApple.MediaKeySession( - this.nativeMediaKeys_, sessionType); -}; + return new PatchedMediaKeysApple.MediaKeySession( + this.nativeMediaKeys_, sessionType); + }; /** @override */ shaka.polyfill.PatchedMediaKeysApple.MediaKeys.prototype .setServerCertificate = function(serverCertificate) { - shaka.log.debug('PatchedMediaKeysApple.MediaKeys.setServerCertificate'); + shaka.log.debug('PatchedMediaKeysApple.MediaKeys.setServerCertificate'); - this.certificate = + this.certificate = serverCertificate ? new Uint8Array(serverCertificate) : null; - return Promise.resolve(true); -}; + return Promise.resolve(true); + }; /** @@ -356,40 +356,40 @@ shaka.polyfill.PatchedMediaKeysApple.MediaKeys.prototype */ shaka.polyfill.PatchedMediaKeysApple.MediaKeys.prototype .setMedia = function(media) { - // Alias - const PatchedMediaKeysApple = shaka.polyfill.PatchedMediaKeysApple; + // Alias + const PatchedMediaKeysApple = shaka.polyfill.PatchedMediaKeysApple; - // Remove any old listeners. - this.eventManager_.removeAll(); + // Remove any old listeners. + this.eventManager_.removeAll(); - // It is valid for media to be null; null is used to flag that event handlers - // need to be cleaned up. - if (!media) { - return Promise.resolve(); - } + // It is valid for media to be null; null is used to flag that event handlers + // need to be cleaned up. + if (!media) { + return Promise.resolve(); + } - // Intercept and translate these prefixed EME events. - this.eventManager_.listen(media, 'webkitneedkey', + // Intercept and translate these prefixed EME events. + this.eventManager_.listen(media, 'webkitneedkey', /** @type {shaka.util.EventManager.ListenerType} */ - (PatchedMediaKeysApple.onWebkitNeedKey_)); + (PatchedMediaKeysApple.onWebkitNeedKey_)); - // Wrap native HTMLMediaElement.webkitSetMediaKeys with a Promise. - try { - // Some browsers require that readyState >=1 before mediaKeys can be set, so - // check this and wait for loadedmetadata if we are not in the correct state - if (media.readyState >= 1) { - media.webkitSetMediaKeys(this.nativeMediaKeys_); - } else { - this.eventManager_.listenOnce(media, 'loadedmetadata', () => { - media.webkitSetMediaKeys(this.nativeMediaKeys_); - }); - } + // Wrap native HTMLMediaElement.webkitSetMediaKeys with a Promise. + try { + // Some browsers require that readyState >=1 before mediaKeys can be set, so + // check this and wait for loadedmetadata if we are not in the correct state + if (media.readyState >= 1) { + media.webkitSetMediaKeys(this.nativeMediaKeys_); + } else { + this.eventManager_.listenOnce(media, 'loadedmetadata', () => { + media.webkitSetMediaKeys(this.nativeMediaKeys_); + }); + } - return Promise.resolve(); - } catch (exception) { - return Promise.reject(exception); - } -}; + return Promise.resolve(); + } catch (exception) { + return Promise.reject(exception); + } + }; /** @@ -404,39 +404,39 @@ shaka.polyfill.PatchedMediaKeysApple.MediaKeys.prototype */ shaka.polyfill.PatchedMediaKeysApple.MediaKeySession = function(nativeMediaKeys, sessionType) { - shaka.log.debug('PatchedMediaKeysApple.MediaKeySession'); - shaka.util.FakeEventTarget.call(this); + shaka.log.debug('PatchedMediaKeysApple.MediaKeySession'); + shaka.util.FakeEventTarget.call(this); - /** The native MediaKeySession, which will be created in generateRequest. + /** The native MediaKeySession, which will be created in generateRequest. * @private {WebKitMediaKeySession} */ - this.nativeMediaKeySession_ = null; + this.nativeMediaKeySession_ = null; - /** @private {WebKitMediaKeys} */ - this.nativeMediaKeys_ = nativeMediaKeys; + /** @private {WebKitMediaKeys} */ + this.nativeMediaKeys_ = nativeMediaKeys; - // Promises that are resolved later - /** @private {shaka.util.PublicPromise} */ - this.generateRequestPromise_ = null; + // Promises that are resolved later + /** @private {shaka.util.PublicPromise} */ + this.generateRequestPromise_ = null; - /** @private {shaka.util.PublicPromise} */ - this.updatePromise_ = null; + /** @private {shaka.util.PublicPromise} */ + this.updatePromise_ = null; - /** @private {!shaka.util.EventManager} */ - this.eventManager_ = new shaka.util.EventManager(); + /** @private {!shaka.util.EventManager} */ + this.eventManager_ = new shaka.util.EventManager(); - /** @type {string} */ - this.sessionId = ''; + /** @type {string} */ + this.sessionId = ''; - /** @type {number} */ - this.expiration = NaN; + /** @type {number} */ + this.expiration = NaN; - /** @type {!shaka.util.PublicPromise} */ - this.closed = new shaka.util.PublicPromise(); + /** @type {!shaka.util.PublicPromise} */ + this.closed = new shaka.util.PublicPromise(); - /** @type {!shaka.polyfill.PatchedMediaKeysApple.MediaKeyStatusMap} */ - this.keyStatuses = + /** @type {!shaka.polyfill.PatchedMediaKeysApple.MediaKeyStatusMap} */ + this.keyStatuses = new shaka.polyfill.PatchedMediaKeysApple.MediaKeyStatusMap(); -}; + }; goog.inherits(shaka.polyfill.PatchedMediaKeysApple.MediaKeySession, shaka.util.FakeEventTarget); @@ -444,93 +444,93 @@ goog.inherits(shaka.polyfill.PatchedMediaKeysApple.MediaKeySession, /** @override */ shaka.polyfill.PatchedMediaKeysApple.MediaKeySession.prototype .generateRequest = function(initDataType, initData) { - shaka.log.debug('PatchedMediaKeysApple.MediaKeySession.generateRequest'); + shaka.log.debug('PatchedMediaKeysApple.MediaKeySession.generateRequest'); - this.generateRequestPromise_ = new shaka.util.PublicPromise(); + this.generateRequestPromise_ = new shaka.util.PublicPromise(); - try { - // This EME spec version requires a MIME content type as the 1st param - // to createSession, but doesn't seem to matter what the value is. - // It also only accepts Uint8Array, not ArrayBuffer, so explicitly make - // initData into a Uint8Array. - this.nativeMediaKeySession_ = this.nativeMediaKeys_.createSession( - 'video/mp4', new Uint8Array(initData)); + try { + // This EME spec version requires a MIME content type as the 1st param + // to createSession, but doesn't seem to matter what the value is. + // It also only accepts Uint8Array, not ArrayBuffer, so explicitly make + // initData into a Uint8Array. + this.nativeMediaKeySession_ = this.nativeMediaKeys_.createSession( + 'video/mp4', new Uint8Array(initData)); - // Attach session event handlers here. - this.eventManager_.listen(this.nativeMediaKeySession_, 'webkitkeymessage', + // Attach session event handlers here. + this.eventManager_.listen(this.nativeMediaKeySession_, 'webkitkeymessage', /** @type {shaka.util.EventManager.ListenerType} */ - (this.onWebkitKeyMessage_.bind(this))); - this.eventManager_.listen(this.nativeMediaKeySession_, 'webkitkeyadded', + (this.onWebkitKeyMessage_.bind(this))); + this.eventManager_.listen(this.nativeMediaKeySession_, 'webkitkeyadded', /** @type {shaka.util.EventManager.ListenerType} */ - (this.onWebkitKeyAdded_.bind(this))); - this.eventManager_.listen(this.nativeMediaKeySession_, 'webkitkeyerror', + (this.onWebkitKeyAdded_.bind(this))); + this.eventManager_.listen(this.nativeMediaKeySession_, 'webkitkeyerror', /** @type {shaka.util.EventManager.ListenerType} */ - (this.onWebkitKeyError_.bind(this))); + (this.onWebkitKeyError_.bind(this))); - this.updateKeyStatus_('status-pending'); - } catch (exception) { - this.generateRequestPromise_.reject(exception); - } + this.updateKeyStatus_('status-pending'); + } catch (exception) { + this.generateRequestPromise_.reject(exception); + } - return this.generateRequestPromise_; -}; + return this.generateRequestPromise_; + }; /** @override */ shaka.polyfill.PatchedMediaKeysApple.MediaKeySession.prototype .load = function() { - shaka.log.debug('PatchedMediaKeysApple.MediaKeySession.load'); + shaka.log.debug('PatchedMediaKeysApple.MediaKeySession.load'); - return Promise.reject(new Error('MediaKeySession.load not yet supported')); -}; + return Promise.reject(new Error('MediaKeySession.load not yet supported')); + }; /** @override */ shaka.polyfill.PatchedMediaKeysApple.MediaKeySession.prototype .update = function(response) { - shaka.log.debug('PatchedMediaKeysApple.MediaKeySession.update'); + shaka.log.debug('PatchedMediaKeysApple.MediaKeySession.update'); - this.updatePromise_ = new shaka.util.PublicPromise(); + this.updatePromise_ = new shaka.util.PublicPromise(); - try { - // Pass through to the native session. - this.nativeMediaKeySession_.update(new Uint8Array(response)); - } catch (exception) { - this.updatePromise_.reject(exception); - } + try { + // Pass through to the native session. + this.nativeMediaKeySession_.update(new Uint8Array(response)); + } catch (exception) { + this.updatePromise_.reject(exception); + } - return this.updatePromise_; -}; + return this.updatePromise_; + }; /** @override */ shaka.polyfill.PatchedMediaKeysApple.MediaKeySession.prototype .close = function() { - shaka.log.debug('PatchedMediaKeysApple.MediaKeySession.close'); + shaka.log.debug('PatchedMediaKeysApple.MediaKeySession.close'); - try { - // Pass through to the native session. - this.nativeMediaKeySession_.close(); + try { + // Pass through to the native session. + this.nativeMediaKeySession_.close(); - this.closed.resolve(); - this.eventManager_.removeAll(); - } catch (exception) { - this.closed.reject(exception); - } + this.closed.resolve(); + this.eventManager_.removeAll(); + } catch (exception) { + this.closed.reject(exception); + } - return this.closed; -}; + return this.closed; + }; /** @override */ shaka.polyfill.PatchedMediaKeysApple.MediaKeySession.prototype .remove = function() { - shaka.log.debug('PatchedMediaKeysApple.MediaKeySession.remove'); + shaka.log.debug('PatchedMediaKeysApple.MediaKeySession.remove'); - return Promise.reject(new Error('MediaKeySession.remove is only ' + + return Promise.reject(new Error('MediaKeySession.remove is only ' + 'applicable for persistent licenses, which are not supported on ' + 'this platform')); -}; + }; /** @@ -543,59 +543,59 @@ shaka.polyfill.PatchedMediaKeysApple.MediaKeySession.prototype */ shaka.polyfill.PatchedMediaKeysApple.rebuildInitData_ = function(initData, certificate) { - // TODO: Move this into DrmEngine if it is still needed with unprefixed EME. - // FairPlay init data is in two parts and must be processed a bit. - // The first part is a 4 byte little-endian int, which is the length of the - // second part. - const initDataArray = new Uint8Array(initData); - const dataview = new DataView(initDataArray.buffer); - const length = dataview.getUint32( + // TODO: Move this into DrmEngine if it is still needed with unprefixed EME. + // FairPlay init data is in two parts and must be processed a bit. + // The first part is a 4 byte little-endian int, which is the length of the + // second part. + const initDataArray = new Uint8Array(initData); + const dataview = new DataView(initDataArray.buffer); + const length = dataview.getUint32( /* position= */ 0, /* littleEndian= */ true); - if (length + 4 != initDataArray.byteLength) { - throw new Error('Malformed init data!'); - } + if (length + 4 != initDataArray.byteLength) { + throw new Error('Malformed init data!'); + } - // The second part is a UTF-16 LE URI from the manifest. - const uriString = shaka.util.StringUtils.fromUTF16( - initDataArray.slice(4), /* littleEndian= */ true); + // The second part is a UTF-16 LE URI from the manifest. + const uriString = shaka.util.StringUtils.fromUTF16( + initDataArray.slice(4), /* littleEndian= */ true); - // The domain of that URI is the content ID according to Apple's FPS sample. - const uri = new goog.Uri(uriString); - const contentId = uri.getDomain(); + // The domain of that URI is the content ID according to Apple's FPS sample. + const uri = new goog.Uri(uriString); + const contentId = uri.getDomain(); - // From that, we build a new init data to use in the session. This is - // composed of several parts. First, the raw init data we already got. - // Second, a 4-byte LE length followed by the content ID in UTF-16-LE. - // Third, a 4-byte LE length followed by the certificate. - const contentIdArray = new Uint8Array( - shaka.util.StringUtils.toUTF16(contentId, /* littleEndian= */ true)); + // From that, we build a new init data to use in the session. This is + // composed of several parts. First, the raw init data we already got. + // Second, a 4-byte LE length followed by the content ID in UTF-16-LE. + // Third, a 4-byte LE length followed by the certificate. + const contentIdArray = new Uint8Array( + shaka.util.StringUtils.toUTF16(contentId, /* littleEndian= */ true)); - const rebuiltInitData = new Uint8Array( - initDataArray.byteLength + + const rebuiltInitData = new Uint8Array( + initDataArray.byteLength + 4 + contentIdArray.byteLength + 4 + certificate.byteLength); - let offset = 0; - /** @param {!Uint8Array} array */ - const append = (array) => { - rebuiltInitData.set(array, offset); - offset += array.byteLength; - }; - /** @param {!Uint8Array} array */ - const appendWithLength = (array) => { - const view = new DataView(rebuiltInitData.buffer); - const value = array.byteLength; - view.setUint32(offset, value, /* littleEndian= */ true); - offset += 4; - append(array); - }; + let offset = 0; + /** @param {!Uint8Array} array */ + const append = (array) => { + rebuiltInitData.set(array, offset); + offset += array.byteLength; + }; + /** @param {!Uint8Array} array */ + const appendWithLength = (array) => { + const view = new DataView(rebuiltInitData.buffer); + const value = array.byteLength; + view.setUint32(offset, value, /* littleEndian= */ true); + offset += 4; + append(array); + }; - append(initDataArray); - appendWithLength(contentIdArray); - appendWithLength(new Uint8Array(certificate)); + append(initDataArray); + appendWithLength(contentIdArray); + appendWithLength(new Uint8Array(certificate)); - return rebuiltInitData; -}; + return rebuiltInitData; + }; /** @@ -610,10 +610,10 @@ shaka.polyfill.PatchedMediaKeysApple.onWebkitNeedKey_ = function(event) { const PatchedMediaKeysApple = shaka.polyfill.PatchedMediaKeysApple; const mediaKeys = - /** @type {shaka.polyfill.PatchedMediaKeysApple.MediaKeys} */( - this.mediaKeys); + /** @type {shaka.polyfill.PatchedMediaKeysApple.MediaKeys} */( + this.mediaKeys); goog.asserts.assert(mediaKeys instanceof PatchedMediaKeysApple.MediaKeys, - 'non-polyfill instance of newMediaKeys'); + 'non-polyfill instance of newMediaKeys'); goog.asserts.assert(event.initData != null, 'missing init data!'); @@ -640,25 +640,25 @@ shaka.polyfill.PatchedMediaKeysApple.onWebkitNeedKey_ = function(event) { */ shaka.polyfill.PatchedMediaKeysApple.MediaKeySession.prototype .onWebkitKeyMessage_ = function(event) { - shaka.log.debug('PatchedMediaKeysApple.onWebkitKeyMessage_', event); + shaka.log.debug('PatchedMediaKeysApple.onWebkitKeyMessage_', event); - // We can now resolve this.generateRequestPromise, which should be non-null. - goog.asserts.assert(this.generateRequestPromise_, - 'generateRequestPromise_ should be set before now!'); - if (this.generateRequestPromise_) { - this.generateRequestPromise_.resolve(); - this.generateRequestPromise_ = null; - } + // We can now resolve this.generateRequestPromise, which should be non-null. + goog.asserts.assert(this.generateRequestPromise_, + 'generateRequestPromise_ should be set before now!'); + if (this.generateRequestPromise_) { + this.generateRequestPromise_.resolve(); + this.generateRequestPromise_ = null; + } - const isNew = this.keyStatuses.getStatus() == undefined; + const isNew = this.keyStatuses.getStatus() == undefined; - const event2 = new shaka.util.FakeEvent('message', { - messageType: isNew ? 'license-request' : 'license-renewal', - message: event.message.buffer, - }); + const event2 = new shaka.util.FakeEvent('message', { + messageType: isNew ? 'license-request' : 'license-renewal', + message: event.message.buffer, + }); - this.dispatchEvent(event2); -}; + this.dispatchEvent(event2); + }; /** @@ -669,22 +669,22 @@ shaka.polyfill.PatchedMediaKeysApple.MediaKeySession.prototype */ shaka.polyfill.PatchedMediaKeysApple.MediaKeySession.prototype .onWebkitKeyAdded_ = function(event) { - shaka.log.debug('PatchedMediaKeysApple.onWebkitKeyAdded_', event); + shaka.log.debug('PatchedMediaKeysApple.onWebkitKeyAdded_', event); - // This shouldn't fire while we're in the middle of generateRequest, but if it - // does, we will need to change the logic to account for it. - goog.asserts.assert(!this.generateRequestPromise_, - 'Key added during generate!'); + // This shouldn't fire while we're in the middle of generateRequest, but if it + // does, we will need to change the logic to account for it. + goog.asserts.assert(!this.generateRequestPromise_, + 'Key added during generate!'); - // We can now resolve this.updatePromise, which should be non-null. - goog.asserts.assert(this.updatePromise_, - 'updatePromise_ should be set before now!'); - if (this.updatePromise_) { - this.updateKeyStatus_('usable'); - this.updatePromise_.resolve(); - this.updatePromise_ = null; - } -}; + // We can now resolve this.updatePromise, which should be non-null. + goog.asserts.assert(this.updatePromise_, + 'updatePromise_ should be set before now!'); + if (this.updatePromise_) { + this.updateKeyStatus_('usable'); + this.updatePromise_.resolve(); + this.updatePromise_ = null; + } + }; /** @@ -695,38 +695,38 @@ shaka.polyfill.PatchedMediaKeysApple.MediaKeySession.prototype */ shaka.polyfill.PatchedMediaKeysApple.MediaKeySession.prototype .onWebkitKeyError_ = function(event) { - shaka.log.debug('PatchedMediaKeysApple.onWebkitKeyError_', event); + shaka.log.debug('PatchedMediaKeysApple.onWebkitKeyError_', event); - const error = new Error('EME PatchedMediaKeysApple key error'); - error.errorCode = this.nativeMediaKeySession_.error; + const error = new Error('EME PatchedMediaKeysApple key error'); + error.errorCode = this.nativeMediaKeySession_.error; - if (this.generateRequestPromise_ != null) { - this.generateRequestPromise_.reject(error); - this.generateRequestPromise_ = null; - } else if (this.updatePromise_ != null) { - this.updatePromise_.reject(error); - this.updatePromise_ = null; - } else { - // Unexpected error - map native codes to standardised key statuses. - // Possible values of this.nativeMediaKeySession_.error.code: - // MEDIA_KEYERR_UNKNOWN = 1 - // MEDIA_KEYERR_CLIENT = 2 - // MEDIA_KEYERR_SERVICE = 3 - // MEDIA_KEYERR_OUTPUT = 4 - // MEDIA_KEYERR_HARDWARECHANGE = 5 - // MEDIA_KEYERR_DOMAIN = 6 + if (this.generateRequestPromise_ != null) { + this.generateRequestPromise_.reject(error); + this.generateRequestPromise_ = null; + } else if (this.updatePromise_ != null) { + this.updatePromise_.reject(error); + this.updatePromise_ = null; + } else { + // Unexpected error - map native codes to standardised key statuses. + // Possible values of this.nativeMediaKeySession_.error.code: + // MEDIA_KEYERR_UNKNOWN = 1 + // MEDIA_KEYERR_CLIENT = 2 + // MEDIA_KEYERR_SERVICE = 3 + // MEDIA_KEYERR_OUTPUT = 4 + // MEDIA_KEYERR_HARDWARECHANGE = 5 + // MEDIA_KEYERR_DOMAIN = 6 - switch (this.nativeMediaKeySession_.error.code) { - case WebKitMediaKeyError.MEDIA_KEYERR_OUTPUT: - case WebKitMediaKeyError.MEDIA_KEYERR_HARDWARECHANGE: - this.updateKeyStatus_('output-not-allowed'); - break; - default: - this.updateKeyStatus_('internal-error'); - break; - } - } -}; + switch (this.nativeMediaKeySession_.error.code) { + case WebKitMediaKeyError.MEDIA_KEYERR_OUTPUT: + case WebKitMediaKeyError.MEDIA_KEYERR_HARDWARECHANGE: + this.updateKeyStatus_('output-not-allowed'); + break; + default: + this.updateKeyStatus_('internal-error'); + break; + } + } + }; /** @@ -737,10 +737,10 @@ shaka.polyfill.PatchedMediaKeysApple.MediaKeySession.prototype */ shaka.polyfill.PatchedMediaKeysApple.MediaKeySession.prototype .updateKeyStatus_ = function(status) { - this.keyStatuses.setStatus(status); - const event = new shaka.util.FakeEvent('keystatuseschange'); - this.dispatchEvent(event); -}; + this.keyStatuses.setStatus(status); + const event = new shaka.util.FakeEvent('keystatuseschange'); + this.dispatchEvent(event); + }; /** @@ -777,9 +777,9 @@ shaka.polyfill.PatchedMediaKeysApple.MediaKeyStatusMap.KEY_ID_; */ shaka.polyfill.PatchedMediaKeysApple.MediaKeyStatusMap.prototype .setStatus = function(status) { - this.size = status == undefined ? 0 : 1; - this.status_ = status; -}; + this.size = status == undefined ? 0 : 1; + this.status_ = status; + }; /** @@ -788,43 +788,43 @@ shaka.polyfill.PatchedMediaKeysApple.MediaKeyStatusMap.prototype */ shaka.polyfill.PatchedMediaKeysApple.MediaKeyStatusMap.prototype .getStatus = function() { - return this.status_; -}; + return this.status_; + }; /** @override */ shaka.polyfill.PatchedMediaKeysApple.MediaKeyStatusMap.prototype .forEach = function(fn) { - if (this.status_) { - const fakeKeyId = + if (this.status_) { + const fakeKeyId = shaka.polyfill.PatchedMediaKeysApple.MediaKeyStatusMap.KEY_ID_; - fn(this.status_, fakeKeyId); - } -}; + fn(this.status_, fakeKeyId); + } + }; /** @override */ shaka.polyfill.PatchedMediaKeysApple.MediaKeyStatusMap.prototype .get = function(keyId) { - if (this.has(keyId)) { - return this.status_; - } - return undefined; -}; + if (this.has(keyId)) { + return this.status_; + } + return undefined; + }; /** @override */ shaka.polyfill.PatchedMediaKeysApple.MediaKeyStatusMap.prototype .has = function(keyId) { - const fakeKeyId = + const fakeKeyId = shaka.polyfill.PatchedMediaKeysApple.MediaKeyStatusMap.KEY_ID_; - if (this.status_ && + if (this.status_ && shaka.util.Uint8ArrayUtils.equal( new Uint8Array(keyId), new Uint8Array(fakeKeyId))) { - return true; - } - return false; -}; + return true; + } + return false; + }; /** @@ -833,8 +833,8 @@ shaka.polyfill.PatchedMediaKeysApple.MediaKeyStatusMap.prototype */ shaka.polyfill.PatchedMediaKeysApple.MediaKeyStatusMap.prototype .entries = function() { - goog.asserts.assert(false, 'Not used! Provided only for the compiler.'); -}; + goog.asserts.assert(false, 'Not used! Provided only for the compiler.'); + }; /** @@ -843,8 +843,8 @@ shaka.polyfill.PatchedMediaKeysApple.MediaKeyStatusMap.prototype */ shaka.polyfill.PatchedMediaKeysApple.MediaKeyStatusMap.prototype .keys = function() { - goog.asserts.assert(false, 'Not used! Provided only for the compiler.'); -}; + goog.asserts.assert(false, 'Not used! Provided only for the compiler.'); + }; /** @@ -853,8 +853,8 @@ shaka.polyfill.PatchedMediaKeysApple.MediaKeyStatusMap.prototype */ shaka.polyfill.PatchedMediaKeysApple.MediaKeyStatusMap.prototype .values = function() { - goog.asserts.assert(false, 'Not used! Provided only for the compiler.'); -}; + goog.asserts.assert(false, 'Not used! Provided only for the compiler.'); + }; shaka.polyfill.register(shaka.polyfill.PatchedMediaKeysApple.install); diff --git a/lib/polyfill/patchedmediakeys_ms.js b/lib/polyfill/patchedmediakeys_ms.js index 981c7a636..d9e2c2d44 100644 --- a/lib/polyfill/patchedmediakeys_ms.js +++ b/lib/polyfill/patchedmediakeys_ms.js @@ -82,20 +82,20 @@ shaka.polyfill.PatchedMediaKeysMs.install = function() { */ shaka.polyfill.PatchedMediaKeysMs.requestMediaKeySystemAccess = function(keySystem, supportedConfigurations) { - shaka.log.debug('PatchedMediaKeysMs.requestMediaKeySystemAccess'); - goog.asserts.assert(this == navigator, - 'bad "this" for requestMediaKeySystemAccess'); + shaka.log.debug('PatchedMediaKeysMs.requestMediaKeySystemAccess'); + goog.asserts.assert(this == navigator, + 'bad "this" for requestMediaKeySystemAccess'); - // Alias. - const PatchedMediaKeysMs = shaka.polyfill.PatchedMediaKeysMs; - try { - const access = new PatchedMediaKeysMs.MediaKeySystemAccess( - keySystem, supportedConfigurations); - return Promise.resolve(/** @type {!MediaKeySystemAccess} */ (access)); - } catch (exception) { - return Promise.reject(exception); - } -}; + // Alias. + const PatchedMediaKeysMs = shaka.polyfill.PatchedMediaKeysMs; + try { + const access = new PatchedMediaKeysMs.MediaKeySystemAccess( + keySystem, supportedConfigurations); + return Promise.resolve(/** @type {!MediaKeySystemAccess} */ (access)); + } catch (exception) { + return Promise.reject(exception); + } + }; /** @@ -110,115 +110,115 @@ shaka.polyfill.PatchedMediaKeysMs.requestMediaKeySystemAccess = */ shaka.polyfill.PatchedMediaKeysMs.MediaKeySystemAccess = function(keySystem, supportedConfigurations) { - shaka.log.debug('PatchedMediaKeysMs.MediaKeySystemAccess'); + shaka.log.debug('PatchedMediaKeysMs.MediaKeySystemAccess'); - /** @type {string} */ - this.keySystem = keySystem; + /** @type {string} */ + this.keySystem = keySystem; - /** @private {!MediaKeySystemConfiguration} */ - this.configuration_; + /** @private {!MediaKeySystemConfiguration} */ + this.configuration_; - const allowPersistentState = false; + const allowPersistentState = false; - let success = false; - for (let i = 0; i < supportedConfigurations.length; ++i) { - const cfg = supportedConfigurations[i]; + let success = false; + for (let i = 0; i < supportedConfigurations.length; ++i) { + const cfg = supportedConfigurations[i]; - // Create a new config object and start adding in the pieces which we - // find support for. We will return this from getConfiguration() if asked. - /** @type {!MediaKeySystemConfiguration} */ - const newCfg = { - 'audioCapabilities': [], - 'videoCapabilities': [], - // It is technically against spec to return these as optional, but we - // don't truly know their values from the prefixed API: - 'persistentState': 'optional', - 'distinctiveIdentifier': 'optional', - // Pretend the requested init data types are supported, since we don't - // really know that either: - 'initDataTypes': cfg.initDataTypes, - 'sessionTypes': ['temporary'], - 'label': cfg.label, + // Create a new config object and start adding in the pieces which we + // find support for. We will return this from getConfiguration() if asked. + /** @type {!MediaKeySystemConfiguration} */ + const newCfg = { + 'audioCapabilities': [], + 'videoCapabilities': [], + // It is technically against spec to return these as optional, but we + // don't truly know their values from the prefixed API: + 'persistentState': 'optional', + 'distinctiveIdentifier': 'optional', + // Pretend the requested init data types are supported, since we don't + // really know that either: + 'initDataTypes': cfg.initDataTypes, + 'sessionTypes': ['temporary'], + 'label': cfg.label, + }; + + // PatchedMediaKeysMs tests for key system availability through + // MSMediaKeys.isTypeSupported + let ranAnyTests = false; + if (cfg.audioCapabilities) { + for (let j = 0; j < cfg.audioCapabilities.length; ++j) { + const cap = cfg.audioCapabilities[j]; + if (cap.contentType) { + ranAnyTests = true; + const contentType = cap.contentType.split(';')[0]; + if (MSMediaKeys.isTypeSupported(this.keySystem, contentType)) { + newCfg.audioCapabilities.push(cap); + success = true; + } + } + } + } + if (cfg.videoCapabilities) { + for (let j = 0; j < cfg.videoCapabilities.length; ++j) { + const cap = cfg.videoCapabilities[j]; + if (cap.contentType) { + ranAnyTests = true; + const contentType = cap.contentType.split(';')[0]; + if (MSMediaKeys.isTypeSupported(this.keySystem, contentType)) { + newCfg.videoCapabilities.push(cap); + success = true; + } + } + } + } + + if (!ranAnyTests) { + // If no specific types were requested, we check all common types to find + // out if the key system is present at all. + success = MSMediaKeys.isTypeSupported(this.keySystem, 'video/mp4'); + } + if (cfg.persistentState == 'required') { + if (allowPersistentState) { + newCfg.persistentState = 'required'; + newCfg.sessionTypes = ['persistent-license']; + } else { + success = false; + } + } + + if (success) { + this.configuration_ = newCfg; + return; + } + } // for each cfg in supportedConfigurations + + // As per the spec, this should be a DOMException, but there is not a public + // constructor for this. + const unsupportedKeySystemError = new Error('Unsupported keySystem'); + unsupportedKeySystemError.name = 'NotSupportedError'; + unsupportedKeySystemError.code = DOMException.NOT_SUPPORTED_ERR; + throw unsupportedKeySystemError; }; - // PatchedMediaKeysMs tests for key system availability through - // MSMediaKeys.isTypeSupported - let ranAnyTests = false; - if (cfg.audioCapabilities) { - for (let j = 0; j < cfg.audioCapabilities.length; ++j) { - const cap = cfg.audioCapabilities[j]; - if (cap.contentType) { - ranAnyTests = true; - const contentType = cap.contentType.split(';')[0]; - if (MSMediaKeys.isTypeSupported(this.keySystem, contentType)) { - newCfg.audioCapabilities.push(cap); - success = true; - } - } - } - } - if (cfg.videoCapabilities) { - for (let j = 0; j < cfg.videoCapabilities.length; ++j) { - const cap = cfg.videoCapabilities[j]; - if (cap.contentType) { - ranAnyTests = true; - const contentType = cap.contentType.split(';')[0]; - if (MSMediaKeys.isTypeSupported(this.keySystem, contentType)) { - newCfg.videoCapabilities.push(cap); - success = true; - } - } - } - } - - if (!ranAnyTests) { - // If no specific types were requested, we check all common types to find - // out if the key system is present at all. - success = MSMediaKeys.isTypeSupported(this.keySystem, 'video/mp4'); - } - if (cfg.persistentState == 'required') { - if (allowPersistentState) { - newCfg.persistentState = 'required'; - newCfg.sessionTypes = ['persistent-license']; - } else { - success = false; - } - } - - if (success) { - this.configuration_ = newCfg; - return; - } - } // for each cfg in supportedConfigurations - - // As per the spec, this should be a DOMException, but there is not a public - // constructor for this. - const unsupportedKeySystemError = new Error('Unsupported keySystem'); - unsupportedKeySystemError.name = 'NotSupportedError'; - unsupportedKeySystemError.code = DOMException.NOT_SUPPORTED_ERR; - throw unsupportedKeySystemError; -}; - /** @override */ shaka.polyfill.PatchedMediaKeysMs.MediaKeySystemAccess.prototype .createMediaKeys = function() { - shaka.log.debug('PatchedMediaKeysMs.MediaKeySystemAccess.createMediaKeys'); + shaka.log.debug('PatchedMediaKeysMs.MediaKeySystemAccess.createMediaKeys'); - // Alias - const PatchedMediaKeysMs = shaka.polyfill.PatchedMediaKeysMs; + // Alias + const PatchedMediaKeysMs = shaka.polyfill.PatchedMediaKeysMs; - const mediaKeys = new PatchedMediaKeysMs.MediaKeys(this.keySystem); - return Promise.resolve(/** @type {!MediaKeys} */ (mediaKeys)); -}; + const mediaKeys = new PatchedMediaKeysMs.MediaKeys(this.keySystem); + return Promise.resolve(/** @type {!MediaKeys} */ (mediaKeys)); + }; /** @override */ shaka.polyfill.PatchedMediaKeysMs.MediaKeySystemAccess.prototype .getConfiguration = function() { - shaka.log.debug('PatchedMediaKeysMs.MediaKeySystemAccess.getConfiguration'); - return this.configuration_; -}; + shaka.log.debug('PatchedMediaKeysMs.MediaKeySystemAccess.getConfiguration'); + return this.configuration_; + }; /** @@ -232,21 +232,21 @@ shaka.polyfill.PatchedMediaKeysMs.MediaKeySystemAccess.prototype shaka.polyfill.PatchedMediaKeysMs.setMediaKeys = function(mediaKeys) { shaka.log.debug('PatchedMediaKeysMs.setMediaKeys'); goog.asserts.assert(this instanceof HTMLMediaElement, - 'bad "this" for setMediaKeys'); + 'bad "this" for setMediaKeys'); // Alias const PatchedMediaKeysMs = shaka.polyfill.PatchedMediaKeysMs; const newMediaKeys = - /** @type {shaka.polyfill.PatchedMediaKeysMs.MediaKeys} */ ( + /** @type {shaka.polyfill.PatchedMediaKeysMs.MediaKeys} */ ( mediaKeys); const oldMediaKeys = - /** @type {shaka.polyfill.PatchedMediaKeysMs.MediaKeys} */ ( + /** @type {shaka.polyfill.PatchedMediaKeysMs.MediaKeys} */ ( this.mediaKeys); if (oldMediaKeys && oldMediaKeys != newMediaKeys) { goog.asserts.assert(oldMediaKeys instanceof PatchedMediaKeysMs.MediaKeys, - 'non-polyfill instance of oldMediaKeys'); + 'non-polyfill instance of oldMediaKeys'); // Have the old MediaKeys stop listening to events on the video tag. oldMediaKeys.setMedia(null); } @@ -256,7 +256,7 @@ shaka.polyfill.PatchedMediaKeysMs.setMediaKeys = function(mediaKeys) { if (newMediaKeys) { goog.asserts.assert(newMediaKeys instanceof PatchedMediaKeysMs.MediaKeys, - 'non-polyfill instance of newMediaKeys'); + 'non-polyfill instance of newMediaKeys'); return newMediaKeys.setMedia(this); } @@ -286,31 +286,31 @@ shaka.polyfill.PatchedMediaKeysMs.MediaKeys = function(keySystem) { /** @override */ shaka.polyfill.PatchedMediaKeysMs.MediaKeys.prototype .createSession = function(sessionType) { - shaka.log.debug('PatchedMediaKeysMs.MediaKeys.createSession'); + shaka.log.debug('PatchedMediaKeysMs.MediaKeys.createSession'); - sessionType = sessionType || 'temporary'; - // For now, only the 'temporary' type is supported. - if (sessionType != 'temporary') { - throw new TypeError('Session type ' + sessionType + + sessionType = sessionType || 'temporary'; + // For now, only the 'temporary' type is supported. + if (sessionType != 'temporary') { + throw new TypeError('Session type ' + sessionType + ' is unsupported on this platform.'); - } + } - // Alias - const PatchedMediaKeysMs = shaka.polyfill.PatchedMediaKeysMs; + // Alias + const PatchedMediaKeysMs = shaka.polyfill.PatchedMediaKeysMs; - return new PatchedMediaKeysMs.MediaKeySession( - this.nativeMediaKeys_, sessionType); -}; + return new PatchedMediaKeysMs.MediaKeySession( + this.nativeMediaKeys_, sessionType); + }; /** @override */ shaka.polyfill.PatchedMediaKeysMs.MediaKeys.prototype .setServerCertificate = function(serverCertificate) { - shaka.log.debug('PatchedMediaKeysMs.MediaKeys.setServerCertificate'); + shaka.log.debug('PatchedMediaKeysMs.MediaKeys.setServerCertificate'); - // There is no equivalent in PatchedMediaKeysMs, so return failure. - return Promise.resolve(false); -}; + // There is no equivalent in PatchedMediaKeysMs, so return failure. + return Promise.resolve(false); + }; /** @@ -320,44 +320,44 @@ shaka.polyfill.PatchedMediaKeysMs.MediaKeys.prototype */ shaka.polyfill.PatchedMediaKeysMs.MediaKeys.prototype .setMedia = function(media) { - // Alias - const PatchedMediaKeysMs = shaka.polyfill.PatchedMediaKeysMs; + // Alias + const PatchedMediaKeysMs = shaka.polyfill.PatchedMediaKeysMs; - // Remove any old listeners. - this.eventManager_.removeAll(); + // Remove any old listeners. + this.eventManager_.removeAll(); - // It is valid for media to be null; null is used to flag that event handlers - // need to be cleaned up. - if (!media) { - return Promise.resolve(); - } + // It is valid for media to be null; null is used to flag that event handlers + // need to be cleaned up. + if (!media) { + return Promise.resolve(); + } - // Intercept and translate these prefixed EME events. - this.eventManager_.listen(media, 'msneedkey', + // Intercept and translate these prefixed EME events. + this.eventManager_.listen(media, 'msneedkey', /** @type {shaka.util.EventManager.ListenerType} */ - (PatchedMediaKeysMs.onMsNeedKey_)); + (PatchedMediaKeysMs.onMsNeedKey_)); - const self = this; - function setMediaKeysDeferred() { - media.msSetMediaKeys(self.nativeMediaKeys_); - media.removeEventListener('loadedmetadata', setMediaKeysDeferred); - } + const self = this; + function setMediaKeysDeferred() { + media.msSetMediaKeys(self.nativeMediaKeys_); + media.removeEventListener('loadedmetadata', setMediaKeysDeferred); + } - // Wrap native HTMLMediaElement.msSetMediaKeys with a Promise. - try { - // IE11/Edge requires that readyState >=1 before mediaKeys can be set, so - // check this and wait for loadedmetadata if we are not in the correct state - if (media.readyState >= 1) { - media.msSetMediaKeys(this.nativeMediaKeys_); - } else { - media.addEventListener('loadedmetadata', setMediaKeysDeferred); - } + // Wrap native HTMLMediaElement.msSetMediaKeys with a Promise. + try { + // IE11/Edge requires that readyState >=1 before mediaKeys can be set, so + // check this and wait for loadedmetadata if we are not in the correct state + if (media.readyState >= 1) { + media.msSetMediaKeys(this.nativeMediaKeys_); + } else { + media.addEventListener('loadedmetadata', setMediaKeysDeferred); + } - return Promise.resolve(); - } catch (exception) { - return Promise.reject(exception); - } -}; + return Promise.resolve(); + } catch (exception) { + return Promise.reject(exception); + } + }; /** @@ -372,39 +372,39 @@ shaka.polyfill.PatchedMediaKeysMs.MediaKeys.prototype */ shaka.polyfill.PatchedMediaKeysMs .MediaKeySession = function(nativeMediaKeys, sessionType) { - shaka.log.debug('PatchedMediaKeysMs.MediaKeySession'); - shaka.util.FakeEventTarget.call(this); + shaka.log.debug('PatchedMediaKeysMs.MediaKeySession'); + shaka.util.FakeEventTarget.call(this); - // The native MediaKeySession, which will be created in generateRequest. - /** @private {MSMediaKeySession} */ - this.nativeMediaKeySession_ = null; + // The native MediaKeySession, which will be created in generateRequest. + /** @private {MSMediaKeySession} */ + this.nativeMediaKeySession_ = null; - /** @private {MSMediaKeys} */ - this.nativeMediaKeys_ = nativeMediaKeys; + /** @private {MSMediaKeys} */ + this.nativeMediaKeys_ = nativeMediaKeys; - // Promises that are resolved later - /** @private {shaka.util.PublicPromise} */ - this.generateRequestPromise_ = null; + // Promises that are resolved later + /** @private {shaka.util.PublicPromise} */ + this.generateRequestPromise_ = null; - /** @private {shaka.util.PublicPromise} */ - this.updatePromise_ = null; + /** @private {shaka.util.PublicPromise} */ + this.updatePromise_ = null; - /** @private {!shaka.util.EventManager} */ - this.eventManager_ = new shaka.util.EventManager(); + /** @private {!shaka.util.EventManager} */ + this.eventManager_ = new shaka.util.EventManager(); - /** @type {string} */ - this.sessionId = ''; + /** @type {string} */ + this.sessionId = ''; - /** @type {number} */ - this.expiration = NaN; + /** @type {number} */ + this.expiration = NaN; - /** @type {!shaka.util.PublicPromise} */ - this.closed = new shaka.util.PublicPromise(); + /** @type {!shaka.util.PublicPromise} */ + this.closed = new shaka.util.PublicPromise(); - /** @type {!shaka.polyfill.PatchedMediaKeysMs.MediaKeyStatusMap} */ - this.keyStatuses = + /** @type {!shaka.polyfill.PatchedMediaKeysMs.MediaKeyStatusMap} */ + this.keyStatuses = new shaka.polyfill.PatchedMediaKeysMs.MediaKeyStatusMap(); -}; + }; goog.inherits(shaka.polyfill.PatchedMediaKeysMs.MediaKeySession, shaka.util.FakeEventTarget); @@ -412,100 +412,100 @@ goog.inherits(shaka.polyfill.PatchedMediaKeysMs.MediaKeySession, /** @override */ shaka.polyfill.PatchedMediaKeysMs.MediaKeySession.prototype .generateRequest = function(initDataType, initData) { - shaka.log.debug('PatchedMediaKeysMs.MediaKeySession.generateRequest'); + shaka.log.debug('PatchedMediaKeysMs.MediaKeySession.generateRequest'); - this.generateRequestPromise_ = new shaka.util.PublicPromise(); + this.generateRequestPromise_ = new shaka.util.PublicPromise(); - try { - // This EME spec version requires a MIME content type as the 1st param - // to createSession, but doesn't seem to matter what the value is. + try { + // This EME spec version requires a MIME content type as the 1st param + // to createSession, but doesn't seem to matter what the value is. - // NOTE: IE11 takes either Uint8Array or ArrayBuffer, but Edge 12 only - // accepts Uint8Array. - this.nativeMediaKeySession_ = this.nativeMediaKeys_ - .createSession('video/mp4', new Uint8Array(initData), null); + // NOTE: IE11 takes either Uint8Array or ArrayBuffer, but Edge 12 only + // accepts Uint8Array. + this.nativeMediaKeySession_ = this.nativeMediaKeys_ + .createSession('video/mp4', new Uint8Array(initData), null); - // Attach session event handlers here. - this.eventManager_.listen(this.nativeMediaKeySession_, 'mskeymessage', + // Attach session event handlers here. + this.eventManager_.listen(this.nativeMediaKeySession_, 'mskeymessage', /** @type {shaka.util.EventManager.ListenerType} */ - (this.onMsKeyMessage_.bind(this))); - this.eventManager_.listen(this.nativeMediaKeySession_, 'mskeyadded', + (this.onMsKeyMessage_.bind(this))); + this.eventManager_.listen(this.nativeMediaKeySession_, 'mskeyadded', /** @type {shaka.util.EventManager.ListenerType} */ - (this.onMsKeyAdded_.bind(this))); - this.eventManager_.listen(this.nativeMediaKeySession_, 'mskeyerror', + (this.onMsKeyAdded_.bind(this))); + this.eventManager_.listen(this.nativeMediaKeySession_, 'mskeyerror', /** @type {shaka.util.EventManager.ListenerType} */ - (this.onMsKeyError_.bind(this))); + (this.onMsKeyError_.bind(this))); - this.updateKeyStatus_('status-pending'); - } catch (exception) { - this.generateRequestPromise_.reject(exception); - } + this.updateKeyStatus_('status-pending'); + } catch (exception) { + this.generateRequestPromise_.reject(exception); + } - return this.generateRequestPromise_; -}; + return this.generateRequestPromise_; + }; /** @override */ shaka.polyfill.PatchedMediaKeysMs.MediaKeySession.prototype .load = function() { - shaka.log.debug('PatchedMediaKeysMs.MediaKeySession.load'); + shaka.log.debug('PatchedMediaKeysMs.MediaKeySession.load'); - return Promise.reject(new Error('MediaKeySession.load not yet supported')); -}; + return Promise.reject(new Error('MediaKeySession.load not yet supported')); + }; /** @override */ shaka.polyfill.PatchedMediaKeysMs.MediaKeySession.prototype .update = function(response) { - shaka.log.debug('PatchedMediaKeysMs.MediaKeySession.update'); + shaka.log.debug('PatchedMediaKeysMs.MediaKeySession.update'); - this.updatePromise_ = new shaka.util.PublicPromise(); + this.updatePromise_ = new shaka.util.PublicPromise(); - try { - // Pass through to the native session. - // NOTE: IE11 takes either Uint8Array or ArrayBuffer, but Edge 12 only - // accepts Uint8Array. - this.nativeMediaKeySession_.update(new Uint8Array(response)); - } catch (exception) { - this.updatePromise_.reject(exception); - } + try { + // Pass through to the native session. + // NOTE: IE11 takes either Uint8Array or ArrayBuffer, but Edge 12 only + // accepts Uint8Array. + this.nativeMediaKeySession_.update(new Uint8Array(response)); + } catch (exception) { + this.updatePromise_.reject(exception); + } - return this.updatePromise_; -}; + return this.updatePromise_; + }; /** @override */ shaka.polyfill.PatchedMediaKeysMs.MediaKeySession.prototype .close = function() { - shaka.log.debug('PatchedMediaKeysMs.MediaKeySession.close'); + shaka.log.debug('PatchedMediaKeysMs.MediaKeySession.close'); - try { - // Pass through to the native session. - // NOTE: IE seems to have a spec discrepancy here - v2010218 should have - // MediaKeySession.release, but actually uses "close". The next version - // of the spec is the initial Promise based one, so it's not the target spec - // either. - this.nativeMediaKeySession_.close(); + try { + // Pass through to the native session. + // NOTE: IE seems to have a spec discrepancy here - v2010218 should have + // MediaKeySession.release, but actually uses "close". The next version + // of the spec is the initial Promise based one, so it's not the target spec + // either. + this.nativeMediaKeySession_.close(); - this.closed.resolve(); - this.eventManager_.removeAll(); - } catch (exception) { - this.closed.reject(exception); - } + this.closed.resolve(); + this.eventManager_.removeAll(); + } catch (exception) { + this.closed.reject(exception); + } - return this.closed; -}; + return this.closed; + }; /** @override */ shaka.polyfill.PatchedMediaKeysMs.MediaKeySession.prototype .remove = function() { - shaka.log.debug('PatchedMediaKeysMs.MediaKeySession.remove'); + shaka.log.debug('PatchedMediaKeysMs.MediaKeySession.remove'); - return Promise.reject(new Error('MediaKeySession.remove is only ' + + return Promise.reject(new Error('MediaKeySession.remove is only ' + 'applicable for persistent licenses, which are not supported on ' + 'this platform')); -}; + }; /** @@ -527,7 +527,7 @@ shaka.polyfill.PatchedMediaKeysMs.onMsNeedKey_ = function(event) { // NOTE: Because "this" is a real EventTarget, on IE, the event we dispatch // here must also be a real Event. const event2 = - /** @type {!CustomEvent} */ (document.createEvent('CustomEvent')); + /** @type {!CustomEvent} */ (document.createEvent('CustomEvent')); event2.initCustomEvent('encrypted', false, false, null); event2.initDataType = 'cenc'; event2.initData = PatchedMediaKeysMs.normaliseInitData_(event.initData); @@ -603,25 +603,25 @@ shaka.polyfill.PatchedMediaKeysMs.normaliseInitData_ = function(initData) { */ shaka.polyfill.PatchedMediaKeysMs.MediaKeySession.prototype .onMsKeyMessage_ = function(event) { - shaka.log.debug('PatchedMediaKeysMs.onMsKeyMessage_', event); + shaka.log.debug('PatchedMediaKeysMs.onMsKeyMessage_', event); - // We can now resolve this.generateRequestPromise, which should be non-null. - goog.asserts.assert(this.generateRequestPromise_, - 'generateRequestPromise_ not set in onMsKeyMessage_'); - if (this.generateRequestPromise_) { - this.generateRequestPromise_.resolve(); - this.generateRequestPromise_ = null; - } + // We can now resolve this.generateRequestPromise, which should be non-null. + goog.asserts.assert(this.generateRequestPromise_, + 'generateRequestPromise_ not set in onMsKeyMessage_'); + if (this.generateRequestPromise_) { + this.generateRequestPromise_.resolve(); + this.generateRequestPromise_ = null; + } - const isNew = this.keyStatuses.getStatus() == undefined; + const isNew = this.keyStatuses.getStatus() == undefined; - const event2 = new shaka.util.FakeEvent('message', { - messageType: isNew ? 'license-request' : 'license-renewal', - message: event.message.buffer, - }); + const event2 = new shaka.util.FakeEvent('message', { + messageType: isNew ? 'license-request' : 'license-renewal', + message: event.message.buffer, + }); - this.dispatchEvent(event2); -}; + this.dispatchEvent(event2); + }; /** @@ -632,31 +632,31 @@ shaka.polyfill.PatchedMediaKeysMs.MediaKeySession.prototype */ shaka.polyfill.PatchedMediaKeysMs.MediaKeySession.prototype .onMsKeyAdded_ = function(event) { - shaka.log.debug('PatchedMediaKeysMs.onMsKeyAdded_', event); + shaka.log.debug('PatchedMediaKeysMs.onMsKeyAdded_', event); - // PlayReady's concept of persistent licenses makes emulation difficult here. - // A license policy can say that the license persists, which causes the CDM to - // store it for use in a later session. The result is that in IE11, the CDM - // fires 'mskeyadded' without ever firing 'mskeymessage'. - if (this.generateRequestPromise_) { - shaka.log.debug('Simulating completion for a PR persistent license.'); - goog.asserts.assert(!this.updatePromise_, - 'updatePromise_ and generateRequestPromise_ set in onMsKeyAdded_'); - this.updateKeyStatus_('usable'); - this.generateRequestPromise_.resolve(); - this.generateRequestPromise_ = null; - return; - } + // PlayReady's concept of persistent licenses makes emulation difficult here. + // A license policy can say that the license persists, which causes the CDM to + // store it for use in a later session. The result is that in IE11, the CDM + // fires 'mskeyadded' without ever firing 'mskeymessage'. + if (this.generateRequestPromise_) { + shaka.log.debug('Simulating completion for a PR persistent license.'); + goog.asserts.assert(!this.updatePromise_, + 'updatePromise_ and generateRequestPromise_ set in onMsKeyAdded_'); + this.updateKeyStatus_('usable'); + this.generateRequestPromise_.resolve(); + this.generateRequestPromise_ = null; + return; + } - // We can now resolve this.updatePromise, which should be non-null. - goog.asserts.assert(this.updatePromise_, - 'updatePromise_ not set in onMsKeyAdded_'); - if (this.updatePromise_) { - this.updateKeyStatus_('usable'); - this.updatePromise_.resolve(); - this.updatePromise_ = null; - } -}; + // We can now resolve this.updatePromise, which should be non-null. + goog.asserts.assert(this.updatePromise_, + 'updatePromise_ not set in onMsKeyAdded_'); + if (this.updatePromise_) { + this.updateKeyStatus_('usable'); + this.updatePromise_.resolve(); + this.updatePromise_ = null; + } + }; /** @@ -667,38 +667,38 @@ shaka.polyfill.PatchedMediaKeysMs.MediaKeySession.prototype */ shaka.polyfill.PatchedMediaKeysMs.MediaKeySession.prototype .onMsKeyError_ = function(event) { - shaka.log.debug('PatchedMediaKeysMs.onMsKeyError_', event); + shaka.log.debug('PatchedMediaKeysMs.onMsKeyError_', event); - const error = new Error('EME PatchedMediaKeysMs key error'); - error.errorCode = this.nativeMediaKeySession_.error; + const error = new Error('EME PatchedMediaKeysMs key error'); + error.errorCode = this.nativeMediaKeySession_.error; - if (this.generateRequestPromise_ != null) { - this.generateRequestPromise_.reject(error); - this.generateRequestPromise_ = null; - } else if (this.updatePromise_ != null) { - this.updatePromise_.reject(error); - this.updatePromise_ = null; - } else { - // Unexpected error - map native codes to standardised key statuses. - // Possible values of this.nativeMediaKeySession_.error.code: - // MS_MEDIA_KEYERR_UNKNOWN = 1 - // MS_MEDIA_KEYERR_CLIENT = 2 - // MS_MEDIA_KEYERR_SERVICE = 3 - // MS_MEDIA_KEYERR_OUTPUT = 4 - // MS_MEDIA_KEYERR_HARDWARECHANGE = 5 - // MS_MEDIA_KEYERR_DOMAIN = 6 + if (this.generateRequestPromise_ != null) { + this.generateRequestPromise_.reject(error); + this.generateRequestPromise_ = null; + } else if (this.updatePromise_ != null) { + this.updatePromise_.reject(error); + this.updatePromise_ = null; + } else { + // Unexpected error - map native codes to standardised key statuses. + // Possible values of this.nativeMediaKeySession_.error.code: + // MS_MEDIA_KEYERR_UNKNOWN = 1 + // MS_MEDIA_KEYERR_CLIENT = 2 + // MS_MEDIA_KEYERR_SERVICE = 3 + // MS_MEDIA_KEYERR_OUTPUT = 4 + // MS_MEDIA_KEYERR_HARDWARECHANGE = 5 + // MS_MEDIA_KEYERR_DOMAIN = 6 - switch (this.nativeMediaKeySession_.error.code) { - case MSMediaKeyError.MS_MEDIA_KEYERR_OUTPUT: - case MSMediaKeyError.MS_MEDIA_KEYERR_HARDWARECHANGE: - this.updateKeyStatus_('output-not-allowed'); - break; - default: - this.updateKeyStatus_('internal-error'); - break; - } - } -}; + switch (this.nativeMediaKeySession_.error.code) { + case MSMediaKeyError.MS_MEDIA_KEYERR_OUTPUT: + case MSMediaKeyError.MS_MEDIA_KEYERR_HARDWARECHANGE: + this.updateKeyStatus_('output-not-allowed'); + break; + default: + this.updateKeyStatus_('internal-error'); + break; + } + } + }; /** @@ -709,10 +709,10 @@ shaka.polyfill.PatchedMediaKeysMs.MediaKeySession.prototype */ shaka.polyfill.PatchedMediaKeysMs.MediaKeySession.prototype .updateKeyStatus_ = function(status) { - this.keyStatuses.setStatus(status); - const event = new shaka.util.FakeEvent('keystatuseschange'); - this.dispatchEvent(event); -}; + this.keyStatuses.setStatus(status); + const event = new shaka.util.FakeEvent('keystatuseschange'); + this.dispatchEvent(event); + }; /** @@ -749,9 +749,9 @@ shaka.polyfill.PatchedMediaKeysMs.MediaKeyStatusMap.KEY_ID_; */ shaka.polyfill.PatchedMediaKeysMs.MediaKeyStatusMap.prototype .setStatus = function(status) { - this.size = status == undefined ? 0 : 1; - this.status_ = status; -}; + this.size = status == undefined ? 0 : 1; + this.status_ = status; + }; /** @@ -760,43 +760,43 @@ shaka.polyfill.PatchedMediaKeysMs.MediaKeyStatusMap.prototype */ shaka.polyfill.PatchedMediaKeysMs.MediaKeyStatusMap.prototype .getStatus = function() { - return this.status_; -}; + return this.status_; + }; /** @override */ shaka.polyfill.PatchedMediaKeysMs.MediaKeyStatusMap.prototype .forEach = function(fn) { - if (this.status_) { - const fakeKeyId = + if (this.status_) { + const fakeKeyId = shaka.polyfill.PatchedMediaKeysMs.MediaKeyStatusMap.KEY_ID_; - fn(this.status_, fakeKeyId); - } -}; + fn(this.status_, fakeKeyId); + } + }; /** @override */ shaka.polyfill.PatchedMediaKeysMs.MediaKeyStatusMap.prototype .get = function(keyId) { - if (this.has(keyId)) { - return this.status_; - } - return undefined; -}; + if (this.has(keyId)) { + return this.status_; + } + return undefined; + }; /** @override */ shaka.polyfill.PatchedMediaKeysMs.MediaKeyStatusMap.prototype .has = function(keyId) { - const fakeKeyId = + const fakeKeyId = shaka.polyfill.PatchedMediaKeysMs.MediaKeyStatusMap.KEY_ID_; - if (this.status_ && + if (this.status_ && shaka.util.Uint8ArrayUtils.equal( new Uint8Array(keyId), new Uint8Array(fakeKeyId))) { - return true; - } - return false; -}; + return true; + } + return false; + }; /** @@ -805,8 +805,8 @@ shaka.polyfill.PatchedMediaKeysMs.MediaKeyStatusMap.prototype */ shaka.polyfill.PatchedMediaKeysMs.MediaKeyStatusMap.prototype .entries = function() { - goog.asserts.assert(false, 'Not used! Provided only for the compiler.'); -}; + goog.asserts.assert(false, 'Not used! Provided only for the compiler.'); + }; /** @@ -815,8 +815,8 @@ shaka.polyfill.PatchedMediaKeysMs.MediaKeyStatusMap.prototype */ shaka.polyfill.PatchedMediaKeysMs.MediaKeyStatusMap.prototype .keys = function() { - goog.asserts.assert(false, 'Not used! Provided only for the compiler.'); -}; + goog.asserts.assert(false, 'Not used! Provided only for the compiler.'); + }; /** @@ -825,8 +825,8 @@ shaka.polyfill.PatchedMediaKeysMs.MediaKeyStatusMap.prototype */ shaka.polyfill.PatchedMediaKeysMs.MediaKeyStatusMap.prototype .values = function() { - goog.asserts.assert(false, 'Not used! Provided only for the compiler.'); -}; + goog.asserts.assert(false, 'Not used! Provided only for the compiler.'); + }; shaka.polyfill.register(shaka.polyfill.PatchedMediaKeysMs.install); diff --git a/lib/polyfill/patchedmediakeys_nop.js b/lib/polyfill/patchedmediakeys_nop.js index c3203ddf1..43a6295b7 100644 --- a/lib/polyfill/patchedmediakeys_nop.js +++ b/lib/polyfill/patchedmediakeys_nop.js @@ -71,14 +71,14 @@ shaka.polyfill.PatchedMediaKeysNop.install = function() { */ shaka.polyfill.PatchedMediaKeysNop.requestMediaKeySystemAccess = function(keySystem, supportedConfigurations) { - shaka.log.debug('PatchedMediaKeysNop.requestMediaKeySystemAccess'); - goog.asserts.assert(this == navigator, - 'bad "this" for requestMediaKeySystemAccess'); + shaka.log.debug('PatchedMediaKeysNop.requestMediaKeySystemAccess'); + goog.asserts.assert(this == navigator, + 'bad "this" for requestMediaKeySystemAccess'); - return Promise.reject(new Error( - 'The key system specified is not supported.')); -}; + return Promise.reject(new Error( + 'The key system specified is not supported.')); + }; /** @@ -92,7 +92,7 @@ shaka.polyfill.PatchedMediaKeysNop.requestMediaKeySystemAccess = shaka.polyfill.PatchedMediaKeysNop.setMediaKeys = function(mediaKeys) { shaka.log.debug('PatchedMediaKeysNop.setMediaKeys'); goog.asserts.assert(this instanceof HTMLMediaElement, - 'bad "this" for setMediaKeys'); + 'bad "this" for setMediaKeys'); if (mediaKeys == null) { return Promise.resolve(); diff --git a/lib/polyfill/patchedmediakeys_webkit.js b/lib/polyfill/patchedmediakeys_webkit.js index d325e0a97..dbc9cf4e4 100644 --- a/lib/polyfill/patchedmediakeys_webkit.js +++ b/lib/polyfill/patchedmediakeys_webkit.js @@ -70,7 +70,7 @@ shaka.polyfill.PatchedMediaKeysWebkit.install = function() { goog.asserts.assert( HTMLMediaElement.prototype[prefixApi('generateKeyRequest')], - 'PatchedMediaKeysWebkit APIs not available!'); + 'PatchedMediaKeysWebkit APIs not available!'); // Construct a fake key ID. This is not done at load-time to avoid exceptions // on unsupported browsers. This particular fake key ID was suggested in @@ -118,20 +118,20 @@ shaka.polyfill.PatchedMediaKeysWebkit.prefixApi_ = function(api) { */ shaka.polyfill.PatchedMediaKeysWebkit.requestMediaKeySystemAccess = function(keySystem, supportedConfigurations) { - shaka.log.debug('PatchedMediaKeysWebkit.requestMediaKeySystemAccess'); - goog.asserts.assert(this == navigator, - 'bad "this" for requestMediaKeySystemAccess'); + shaka.log.debug('PatchedMediaKeysWebkit.requestMediaKeySystemAccess'); + goog.asserts.assert(this == navigator, + 'bad "this" for requestMediaKeySystemAccess'); - // Alias. - const PatchedMediaKeysWebkit = shaka.polyfill.PatchedMediaKeysWebkit; - try { - const access = new PatchedMediaKeysWebkit.MediaKeySystemAccess( - keySystem, supportedConfigurations); - return Promise.resolve(/** @type {!MediaKeySystemAccess} */ (access)); - } catch (exception) { - return Promise.reject(exception); - } -}; + // Alias. + const PatchedMediaKeysWebkit = shaka.polyfill.PatchedMediaKeysWebkit; + try { + const access = new PatchedMediaKeysWebkit.MediaKeySystemAccess( + keySystem, supportedConfigurations); + return Promise.resolve(/** @type {!MediaKeySystemAccess} */ (access)); + } catch (exception) { + return Promise.reject(exception); + } + }; /** @@ -145,17 +145,17 @@ shaka.polyfill.PatchedMediaKeysWebkit.requestMediaKeySystemAccess = shaka.polyfill.PatchedMediaKeysWebkit.setMediaKeys = function(mediaKeys) { shaka.log.debug('PatchedMediaKeysWebkit.setMediaKeys'); goog.asserts.assert(this instanceof HTMLMediaElement, - 'bad "this" for setMediaKeys'); + 'bad "this" for setMediaKeys'); // Alias. const PatchedMediaKeysWebkit = shaka.polyfill.PatchedMediaKeysWebkit; const newMediaKeys = - /** @type {shaka.polyfill.PatchedMediaKeysWebkit.MediaKeys} */ ( - mediaKeys); + /** @type {shaka.polyfill.PatchedMediaKeysWebkit.MediaKeys} */ ( + mediaKeys); const oldMediaKeys = - /** @type {shaka.polyfill.PatchedMediaKeysWebkit.MediaKeys} */ ( - this.mediaKeys); + /** @type {shaka.polyfill.PatchedMediaKeysWebkit.MediaKeys} */ ( + this.mediaKeys); if (oldMediaKeys && oldMediaKeys != newMediaKeys) { goog.asserts.assert( @@ -207,134 +207,134 @@ shaka.polyfill.PatchedMediaKeysWebkit.getVideoElement_ = function() { */ shaka.polyfill.PatchedMediaKeysWebkit.MediaKeySystemAccess = function(keySystem, supportedConfigurations) { - shaka.log.debug('PatchedMediaKeysWebkit.MediaKeySystemAccess'); + shaka.log.debug('PatchedMediaKeysWebkit.MediaKeySystemAccess'); - /** @type {string} */ - this.keySystem = keySystem; + /** @type {string} */ + this.keySystem = keySystem; - /** @private {string} */ - this.internalKeySystem_ = keySystem; + /** @private {string} */ + this.internalKeySystem_ = keySystem; - /** @private {!MediaKeySystemConfiguration} */ - this.configuration_; + /** @private {!MediaKeySystemConfiguration} */ + this.configuration_; - // This is only a guess, since we don't really know from the prefixed API. - let allowPersistentState = false; + // This is only a guess, since we don't really know from the prefixed API. + let allowPersistentState = false; - if (keySystem == 'org.w3.clearkey') { - // ClearKey's string must be prefixed in v0.1b. - this.internalKeySystem_ = 'webkit-org.w3.clearkey'; - // ClearKey doesn't support persistence. - allowPersistentState = false; - } + if (keySystem == 'org.w3.clearkey') { + // ClearKey's string must be prefixed in v0.1b. + this.internalKeySystem_ = 'webkit-org.w3.clearkey'; + // ClearKey doesn't support persistence. + allowPersistentState = false; + } - let success = false; - const tmpVideo = shaka.polyfill.PatchedMediaKeysWebkit.getVideoElement_(); - for (let i = 0; i < supportedConfigurations.length; ++i) { - const cfg = supportedConfigurations[i]; + let success = false; + const tmpVideo = shaka.polyfill.PatchedMediaKeysWebkit.getVideoElement_(); + for (let i = 0; i < supportedConfigurations.length; ++i) { + const cfg = supportedConfigurations[i]; - // Create a new config object and start adding in the pieces which we - // find support for. We will return this from getConfiguration() if asked. - /** @type {!MediaKeySystemConfiguration} */ - const newCfg = { - 'audioCapabilities': [], - 'videoCapabilities': [], - // It is technically against spec to return these as optional, but we - // don't truly know their values from the prefixed API: - 'persistentState': 'optional', - 'distinctiveIdentifier': 'optional', - // Pretend the requested init data types are supported, since we don't - // really know that either: - 'initDataTypes': cfg.initDataTypes, - 'sessionTypes': ['temporary'], - 'label': cfg.label, - }; + // Create a new config object and start adding in the pieces which we + // find support for. We will return this from getConfiguration() if asked. + /** @type {!MediaKeySystemConfiguration} */ + const newCfg = { + 'audioCapabilities': [], + 'videoCapabilities': [], + // It is technically against spec to return these as optional, but we + // don't truly know their values from the prefixed API: + 'persistentState': 'optional', + 'distinctiveIdentifier': 'optional', + // Pretend the requested init data types are supported, since we don't + // really know that either: + 'initDataTypes': cfg.initDataTypes, + 'sessionTypes': ['temporary'], + 'label': cfg.label, + }; - // v0.1b tests for key system availability with an extra argument on - // canPlayType. - let ranAnyTests = false; - if (cfg.audioCapabilities) { - for (let j = 0; j < cfg.audioCapabilities.length; ++j) { - const cap = cfg.audioCapabilities[j]; - if (cap.contentType) { - ranAnyTests = true; - // In Chrome <= 40, if you ask about Widevine-encrypted audio support, - // you get a false-negative when you specify codec information. - // Work around this by stripping codec info for audio types. - const contentType = cap.contentType.split(';')[0]; - if (tmpVideo.canPlayType(contentType, this.internalKeySystem_)) { - newCfg.audioCapabilities.push(cap); - success = true; + // v0.1b tests for key system availability with an extra argument on + // canPlayType. + let ranAnyTests = false; + if (cfg.audioCapabilities) { + for (let j = 0; j < cfg.audioCapabilities.length; ++j) { + const cap = cfg.audioCapabilities[j]; + if (cap.contentType) { + ranAnyTests = true; + // In Chrome <= 40, if you ask about Widevine-encrypted audio support, + // you get a false-negative when you specify codec information. + // Work around this by stripping codec info for audio types. + const contentType = cap.contentType.split(';')[0]; + if (tmpVideo.canPlayType(contentType, this.internalKeySystem_)) { + newCfg.audioCapabilities.push(cap); + success = true; + } + } } } - } - } - if (cfg.videoCapabilities) { - for (let j = 0; j < cfg.videoCapabilities.length; ++j) { - const cap = cfg.videoCapabilities[j]; - if (cap.contentType) { - ranAnyTests = true; - if (tmpVideo.canPlayType(cap.contentType, this.internalKeySystem_)) { - newCfg.videoCapabilities.push(cap); - success = true; + if (cfg.videoCapabilities) { + for (let j = 0; j < cfg.videoCapabilities.length; ++j) { + const cap = cfg.videoCapabilities[j]; + if (cap.contentType) { + ranAnyTests = true; + if (tmpVideo.canPlayType(cap.contentType, this.internalKeySystem_)) { + newCfg.videoCapabilities.push(cap); + success = true; + } + } } } - } - } - if (!ranAnyTests) { - // If no specific types were requested, we check all common types to find - // out if the key system is present at all. - success = tmpVideo.canPlayType('video/mp4', this.internalKeySystem_) || + if (!ranAnyTests) { + // If no specific types were requested, we check all common types to find + // out if the key system is present at all. + success = tmpVideo.canPlayType('video/mp4', this.internalKeySystem_) || tmpVideo.canPlayType('video/webm', this.internalKeySystem_); - } - if (cfg.persistentState == 'required') { - if (allowPersistentState) { - newCfg.persistentState = 'required'; - newCfg.sessionTypes = ['persistent-license']; - } else { - success = false; + } + if (cfg.persistentState == 'required') { + if (allowPersistentState) { + newCfg.persistentState = 'required'; + newCfg.sessionTypes = ['persistent-license']; + } else { + success = false; + } + } + + if (success) { + this.configuration_ = newCfg; + return; + } + } // for each cfg in supportedConfigurations + + let message = 'Unsupported keySystem'; + if (keySystem == 'org.w3.clearkey' || keySystem == 'com.widevine.alpha') { + message = 'None of the requested configurations were supported.'; } - } - - if (success) { - this.configuration_ = newCfg; - return; - } - } // for each cfg in supportedConfigurations - - let message = 'Unsupported keySystem'; - if (keySystem == 'org.w3.clearkey' || keySystem == 'com.widevine.alpha') { - message = 'None of the requested configurations were supported.'; - } - const unsupportedError = new Error(message); - unsupportedError.name = 'NotSupportedError'; - unsupportedError.code = DOMException.NOT_SUPPORTED_ERR; - throw unsupportedError; -}; + const unsupportedError = new Error(message); + unsupportedError.name = 'NotSupportedError'; + unsupportedError.code = DOMException.NOT_SUPPORTED_ERR; + throw unsupportedError; + }; /** @override */ shaka.polyfill.PatchedMediaKeysWebkit.MediaKeySystemAccess.prototype .createMediaKeys = function() { - shaka.log.debug( - 'PatchedMediaKeysWebkit.MediaKeySystemAccess.createMediaKeys'); + shaka.log.debug( + 'PatchedMediaKeysWebkit.MediaKeySystemAccess.createMediaKeys'); - // Alias. - const PatchedMediaKeysWebkit = shaka.polyfill.PatchedMediaKeysWebkit; - const mediaKeys = + // Alias. + const PatchedMediaKeysWebkit = shaka.polyfill.PatchedMediaKeysWebkit; + const mediaKeys = new PatchedMediaKeysWebkit.MediaKeys(this.internalKeySystem_); - return Promise.resolve(/** @type {!MediaKeys} */ (mediaKeys)); -}; + return Promise.resolve(/** @type {!MediaKeys} */ (mediaKeys)); + }; /** @override */ shaka.polyfill.PatchedMediaKeysWebkit.MediaKeySystemAccess.prototype .getConfiguration = function() { - shaka.log.debug( - 'PatchedMediaKeysWebkit.MediaKeySystemAccess.getConfiguration'); - return this.configuration_; -}; + shaka.log.debug( + 'PatchedMediaKeysWebkit.MediaKeySystemAccess.getConfiguration'); + return this.configuration_; + }; /** @@ -376,70 +376,70 @@ shaka.polyfill.PatchedMediaKeysWebkit.MediaKeys = function(keySystem) { */ shaka.polyfill.PatchedMediaKeysWebkit.MediaKeys.prototype.setMedia = function(media) { - this.media_ = media; + this.media_ = media; - // Remove any old listeners. - this.eventManager_.removeAll(); + // Remove any old listeners. + this.eventManager_.removeAll(); - const prefix = shaka.polyfill.PatchedMediaKeysWebkit.prefix_; - if (media) { - // Intercept and translate these prefixed EME events. - this.eventManager_.listen(media, prefix + 'needkey', + const prefix = shaka.polyfill.PatchedMediaKeysWebkit.prefix_; + if (media) { + // Intercept and translate these prefixed EME events. + this.eventManager_.listen(media, prefix + 'needkey', /** @type {shaka.util.EventManager.ListenerType} */ ( - this.onWebkitNeedKey_.bind(this))); + this.onWebkitNeedKey_.bind(this))); - this.eventManager_.listen(media, prefix + 'keymessage', + this.eventManager_.listen(media, prefix + 'keymessage', /** @type {shaka.util.EventManager.ListenerType} */ ( - this.onWebkitKeyMessage_.bind(this))); + this.onWebkitKeyMessage_.bind(this))); - this.eventManager_.listen(media, prefix + 'keyadded', + this.eventManager_.listen(media, prefix + 'keyadded', /** @type {shaka.util.EventManager.ListenerType} */ ( - this.onWebkitKeyAdded_.bind(this))); + this.onWebkitKeyAdded_.bind(this))); - this.eventManager_.listen(media, prefix + 'keyerror', + this.eventManager_.listen(media, prefix + 'keyerror', /** @type {shaka.util.EventManager.ListenerType} */ ( - this.onWebkitKeyError_.bind(this))); - } -}; + this.onWebkitKeyError_.bind(this))); + } + }; /** @override */ shaka.polyfill.PatchedMediaKeysWebkit.MediaKeys.prototype.createSession = function(sessionType) { - shaka.log.debug('PatchedMediaKeysWebkit.MediaKeys.createSession'); + shaka.log.debug('PatchedMediaKeysWebkit.MediaKeys.createSession'); - sessionType = sessionType || 'temporary'; - if (sessionType != 'temporary' && sessionType != 'persistent-license') { - throw new TypeError('Session type ' + sessionType + + sessionType = sessionType || 'temporary'; + if (sessionType != 'temporary' && sessionType != 'persistent-license') { + throw new TypeError('Session type ' + sessionType + ' is unsupported on this platform.'); - } + } - // Alias. - const PatchedMediaKeysWebkit = shaka.polyfill.PatchedMediaKeysWebkit; + // Alias. + const PatchedMediaKeysWebkit = shaka.polyfill.PatchedMediaKeysWebkit; - // Unprefixed EME allows for session creation without a video tag or src. - // Prefixed EME requires both a valid HTMLMediaElement and a src. - const media = this.media_ || /** @type {!HTMLMediaElement} */( - document.createElement('video')); - if (!media.src) { - media.src = 'about:blank'; - } + // Unprefixed EME allows for session creation without a video tag or src. + // Prefixed EME requires both a valid HTMLMediaElement and a src. + const media = this.media_ || /** @type {!HTMLMediaElement} */( + document.createElement('video')); + if (!media.src) { + media.src = 'about:blank'; + } - const session = new PatchedMediaKeysWebkit.MediaKeySession( - media, this.keySystem_, sessionType); - this.newSessions_.push(session); - return session; -}; + const session = new PatchedMediaKeysWebkit.MediaKeySession( + media, this.keySystem_, sessionType); + this.newSessions_.push(session); + return session; + }; /** @override */ shaka.polyfill.PatchedMediaKeysWebkit.MediaKeys.prototype.setServerCertificate = function(serverCertificate) { - shaka.log.debug('PatchedMediaKeysWebkit.MediaKeys.setServerCertificate'); + shaka.log.debug('PatchedMediaKeysWebkit.MediaKeys.setServerCertificate'); - // There is no equivalent in v0.1b, so return failure. - return Promise.resolve(false); -}; + // There is no equivalent in v0.1b, so return failure. + return Promise.resolve(false); + }; /** @@ -448,19 +448,19 @@ shaka.polyfill.PatchedMediaKeysWebkit.MediaKeys.prototype.setServerCertificate = */ shaka.polyfill.PatchedMediaKeysWebkit.MediaKeys.prototype.onWebkitNeedKey_ = function(event) { - shaka.log.debug('PatchedMediaKeysWebkit.onWebkitNeedKey_', event); - goog.asserts.assert(this.media_, 'media_ not set in onWebkitNeedKey_'); + shaka.log.debug('PatchedMediaKeysWebkit.onWebkitNeedKey_', event); + goog.asserts.assert(this.media_, 'media_ not set in onWebkitNeedKey_'); - const event2 = + const event2 = /** @type {!CustomEvent} */ (document.createEvent('CustomEvent')); - event2.initCustomEvent('encrypted', false, false, null); + event2.initCustomEvent('encrypted', false, false, null); - // not used by v0.1b EME, but given a valid value - event2.initDataType = 'webm'; - event2.initData = event.initData; + // not used by v0.1b EME, but given a valid value + event2.initDataType = 'webm'; + event2.initData = event.initData; - this.media_.dispatchEvent(event2); -}; + this.media_.dispatchEvent(event2); + }; /** @@ -469,24 +469,24 @@ shaka.polyfill.PatchedMediaKeysWebkit.MediaKeys.prototype.onWebkitNeedKey_ = */ shaka.polyfill.PatchedMediaKeysWebkit.MediaKeys.prototype.onWebkitKeyMessage_ = function(event) { - shaka.log.debug('PatchedMediaKeysWebkit.onWebkitKeyMessage_', event); + shaka.log.debug('PatchedMediaKeysWebkit.onWebkitKeyMessage_', event); - const session = this.findSession_(event.sessionId); - if (!session) { - shaka.log.error('Session not found', event.sessionId); - return; - } + const session = this.findSession_(event.sessionId); + if (!session) { + shaka.log.error('Session not found', event.sessionId); + return; + } - const isNew = session.keyStatuses.getStatus() == undefined; + const isNew = session.keyStatuses.getStatus() == undefined; - const event2 = new shaka.util.FakeEvent('message', { - messageType: isNew ? 'licenserequest' : 'licenserenewal', - message: event.message, - }); + const event2 = new shaka.util.FakeEvent('message', { + messageType: isNew ? 'licenserequest' : 'licenserenewal', + message: event.message, + }); - session.generated(); - session.dispatchEvent(event2); -}; + session.generated(); + session.dispatchEvent(event2); + }; /** @@ -495,14 +495,14 @@ shaka.polyfill.PatchedMediaKeysWebkit.MediaKeys.prototype.onWebkitKeyMessage_ = */ shaka.polyfill.PatchedMediaKeysWebkit.MediaKeys.prototype.onWebkitKeyAdded_ = function(event) { - shaka.log.debug('PatchedMediaKeysWebkit.onWebkitKeyAdded_', event); + shaka.log.debug('PatchedMediaKeysWebkit.onWebkitKeyAdded_', event); - const session = this.findSession_(event.sessionId); - goog.asserts.assert(session, 'unable to find session in onWebkitKeyAdded_'); - if (session) { - session.ready(); - } -}; + const session = this.findSession_(event.sessionId); + goog.asserts.assert(session, 'unable to find session in onWebkitKeyAdded_'); + if (session) { + session.ready(); + } + }; /** @@ -511,14 +511,14 @@ shaka.polyfill.PatchedMediaKeysWebkit.MediaKeys.prototype.onWebkitKeyAdded_ = */ shaka.polyfill.PatchedMediaKeysWebkit.MediaKeys.prototype.onWebkitKeyError_ = function(event) { - shaka.log.debug('PatchedMediaKeysWebkit.onWebkitKeyError_', event); + shaka.log.debug('PatchedMediaKeysWebkit.onWebkitKeyError_', event); - const session = this.findSession_(event.sessionId); - goog.asserts.assert(session, 'unable to find session in onWebkitKeyError_'); - if (session) { - session.handleError(event); - } -}; + const session = this.findSession_(event.sessionId); + goog.asserts.assert(session, 'unable to find session in onWebkitKeyError_'); + if (session) { + session.handleError(event); + } + }; /** @@ -528,22 +528,22 @@ shaka.polyfill.PatchedMediaKeysWebkit.MediaKeys.prototype.onWebkitKeyError_ = */ shaka.polyfill.PatchedMediaKeysWebkit.MediaKeys.prototype.findSession_ = function(sessionId) { - let session = this.sessionMap_[sessionId]; - if (session) { - shaka.log.debug('PatchedMediaKeysWebkit.MediaKeys.findSession_', session); - return session; - } + let session = this.sessionMap_[sessionId]; + if (session) { + shaka.log.debug('PatchedMediaKeysWebkit.MediaKeys.findSession_', session); + return session; + } - session = this.newSessions_.shift(); - if (session) { - session.sessionId = sessionId; - this.sessionMap_[sessionId] = session; - shaka.log.debug('PatchedMediaKeysWebkit.MediaKeys.findSession_', session); - return session; - } + session = this.newSessions_.shift(); + if (session) { + session.sessionId = sessionId; + this.sessionMap_[sessionId] = session; + shaka.log.debug('PatchedMediaKeysWebkit.MediaKeys.findSession_', session); + return session; + } - return null; -}; + return null; + }; /** @@ -560,42 +560,42 @@ shaka.polyfill.PatchedMediaKeysWebkit.MediaKeys.prototype.findSession_ = */ shaka.polyfill.PatchedMediaKeysWebkit.MediaKeySession = function(media, keySystem, sessionType) { - shaka.log.debug('PatchedMediaKeysWebkit.MediaKeySession'); - shaka.util.FakeEventTarget.call(this); + shaka.log.debug('PatchedMediaKeysWebkit.MediaKeySession'); + shaka.util.FakeEventTarget.call(this); - /** @private {!HTMLMediaElement} */ - this.media_ = media; + /** @private {!HTMLMediaElement} */ + this.media_ = media; - /** @private {boolean} */ - this.initialized_ = false; + /** @private {boolean} */ + this.initialized_ = false; - /** @private {shaka.util.PublicPromise} */ - this.generatePromise_ = null; + /** @private {shaka.util.PublicPromise} */ + this.generatePromise_ = null; - /** @private {shaka.util.PublicPromise} */ - this.updatePromise_ = null; + /** @private {shaka.util.PublicPromise} */ + this.updatePromise_ = null; - /** @private {string} */ - this.keySystem_ = keySystem; + /** @private {string} */ + this.keySystem_ = keySystem; - /** @private {string} */ - this.type_ = sessionType; + /** @private {string} */ + this.type_ = sessionType; - /** @type {string} */ - this.sessionId = ''; + /** @type {string} */ + this.sessionId = ''; - /** @type {number} */ - this.expiration = NaN; + /** @type {number} */ + this.expiration = NaN; - /** @type {!shaka.util.PublicPromise} */ - this.closed = new shaka.util.PublicPromise(); + /** @type {!shaka.util.PublicPromise} */ + this.closed = new shaka.util.PublicPromise(); - /** @type {!shaka.polyfill.PatchedMediaKeysWebkit.MediaKeyStatusMap} */ - this.keyStatuses = + /** @type {!shaka.polyfill.PatchedMediaKeysWebkit.MediaKeyStatusMap} */ + this.keyStatuses = new shaka.polyfill.PatchedMediaKeysWebkit.MediaKeyStatusMap(); -}; + }; goog.inherits(shaka.polyfill.PatchedMediaKeysWebkit.MediaKeySession, - shaka.util.FakeEventTarget); + shaka.util.FakeEventTarget); /** @@ -606,13 +606,13 @@ goog.inherits(shaka.polyfill.PatchedMediaKeysWebkit.MediaKeySession, */ shaka.polyfill.PatchedMediaKeysWebkit.MediaKeySession.prototype.generated = function() { - shaka.log.debug('PatchedMediaKeysWebkit.MediaKeySession.generated'); + shaka.log.debug('PatchedMediaKeysWebkit.MediaKeySession.generated'); - if (this.generatePromise_) { - this.generatePromise_.resolve(); - this.generatePromise_ = null; - } -}; + if (this.generatePromise_) { + this.generatePromise_.resolve(); + this.generatePromise_ = null; + } + }; /** @@ -624,15 +624,15 @@ shaka.polyfill.PatchedMediaKeysWebkit.MediaKeySession.prototype.generated = */ shaka.polyfill.PatchedMediaKeysWebkit.MediaKeySession.prototype.ready = function() { - shaka.log.debug('PatchedMediaKeysWebkit.MediaKeySession.ready'); + shaka.log.debug('PatchedMediaKeysWebkit.MediaKeySession.ready'); - this.updateKeyStatus_('usable'); + this.updateKeyStatus_('usable'); - if (this.updatePromise_) { - this.updatePromise_.resolve(); - } - this.updatePromise_ = null; -}; + if (this.updatePromise_) { + this.updatePromise_.resolve(); + } + this.updatePromise_ = null; + }; /** @@ -642,41 +642,41 @@ shaka.polyfill.PatchedMediaKeysWebkit.MediaKeySession.prototype.ready = */ shaka.polyfill.PatchedMediaKeysWebkit.MediaKeySession.prototype.handleError = function(event) { - shaka.log.debug('PatchedMediaKeysWebkit.MediaKeySession.handleError', event); + shaka.log.debug('PatchedMediaKeysWebkit.MediaKeySession.handleError', event); - // This does not match the DOMException we get in current WD EME, but it will - // at least provide some information which can be used to look into the - // problem. - const error = new Error('EME v0.1b key error'); - error.errorCode = event.errorCode; - error.errorCode.systemCode = event.systemCode; + // This does not match the DOMException we get in current WD EME, but it will + // at least provide some information which can be used to look into the + // problem. + const error = new Error('EME v0.1b key error'); + error.errorCode = event.errorCode; + error.errorCode.systemCode = event.systemCode; - // The presence or absence of sessionId indicates whether this corresponds to - // generateRequest() or update(). - if (!event.sessionId && this.generatePromise_) { - error.method = 'generateRequest'; - if (event.systemCode == 45) { - error.message = 'Unsupported session type.'; - } - this.generatePromise_.reject(error); - this.generatePromise_ = null; - } else if (event.sessionId && this.updatePromise_) { - error.method = 'update'; - this.updatePromise_.reject(error); - this.updatePromise_ = null; - } else { - // This mapping of key statuses is imperfect at best. - const code = event.errorCode.code; - const systemCode = event.systemCode; - if (code == MediaKeyError['MEDIA_KEYERR_OUTPUT']) { - this.updateKeyStatus_('output-restricted'); - } else if (systemCode == 1) { - this.updateKeyStatus_('expired'); - } else { - this.updateKeyStatus_('internal-error'); - } - } -}; + // The presence or absence of sessionId indicates whether this corresponds to + // generateRequest() or update(). + if (!event.sessionId && this.generatePromise_) { + error.method = 'generateRequest'; + if (event.systemCode == 45) { + error.message = 'Unsupported session type.'; + } + this.generatePromise_.reject(error); + this.generatePromise_ = null; + } else if (event.sessionId && this.updatePromise_) { + error.method = 'update'; + this.updatePromise_.reject(error); + this.updatePromise_ = null; + } else { + // This mapping of key statuses is imperfect at best. + const code = event.errorCode.code; + const systemCode = event.systemCode; + if (code == MediaKeyError['MEDIA_KEYERR_OUTPUT']) { + this.updateKeyStatus_('output-restricted'); + } else if (systemCode == 1) { + this.updateKeyStatus_('expired'); + } else { + this.updateKeyStatus_('internal-error'); + } + } + }; /** @@ -690,84 +690,84 @@ shaka.polyfill.PatchedMediaKeysWebkit.MediaKeySession.prototype.handleError = */ shaka.polyfill.PatchedMediaKeysWebkit.MediaKeySession.prototype.generate_ = function(initData, offlineSessionId) { - if (this.initialized_) { - return Promise.reject(new Error('The session is already initialized.')); - } - - this.initialized_ = true; - - /** @type {!Uint8Array} */ - let mangledInitData; - - try { - if (this.type_ == 'persistent-license') { - const StringUtils = shaka.util.StringUtils; - if (!offlineSessionId) { - // Persisting the initial license. - // Prefix the init data with a tag to indicate persistence. - const prefix = StringUtils.toUTF8('PERSISTENT|'); - const result = new Uint8Array(prefix.byteLength + initData.byteLength); - result.set(new Uint8Array(prefix), 0); - result.set(new Uint8Array(initData), prefix.byteLength); - mangledInitData = result; - } else { - // Loading a stored license. - // Prefix the init data (which is really a session ID) with a tag to - // indicate that we are loading a persisted session. - mangledInitData = new Uint8Array( - StringUtils.toUTF8('LOAD_SESSION|' + offlineSessionId)); + if (this.initialized_) { + return Promise.reject(new Error('The session is already initialized.')); } - } else { - // Streaming. - goog.asserts.assert(this.type_ == 'temporary', - 'expected temporary session'); - goog.asserts.assert(!offlineSessionId, - 'unexpected offline session ID'); - mangledInitData = new Uint8Array(initData); - } - goog.asserts.assert(mangledInitData, - 'init data not set!'); - } catch (exception) { - return Promise.reject(exception); - } + this.initialized_ = true; - goog.asserts.assert(this.generatePromise_ == null, - 'generatePromise_ should be null'); - this.generatePromise_ = new shaka.util.PublicPromise(); + /** @type {!Uint8Array} */ + let mangledInitData; - // Because we are hacking media.src in createSession to better emulate - // unprefixed EME's ability to create sessions and license requests without a - // video tag, we can get ourselves into trouble. It seems that sometimes, - // the setting of media.src hasn't been processed by some other thread, and - // GKR can throw an exception. If this occurs, wait 10 ms and try again at - // most once. This situation should only occur when init data is available - // ahead of the 'needkey' event. + try { + if (this.type_ == 'persistent-license') { + const StringUtils = shaka.util.StringUtils; + if (!offlineSessionId) { + // Persisting the initial license. + // Prefix the init data with a tag to indicate persistence. + const prefix = StringUtils.toUTF8('PERSISTENT|'); + const result = new Uint8Array(prefix.byteLength + initData.byteLength); + result.set(new Uint8Array(prefix), 0); + result.set(new Uint8Array(initData), prefix.byteLength); + mangledInitData = result; + } else { + // Loading a stored license. + // Prefix the init data (which is really a session ID) with a tag to + // indicate that we are loading a persisted session. + mangledInitData = new Uint8Array( + StringUtils.toUTF8('LOAD_SESSION|' + offlineSessionId)); + } + } else { + // Streaming. + goog.asserts.assert(this.type_ == 'temporary', + 'expected temporary session'); + goog.asserts.assert(!offlineSessionId, + 'unexpected offline session ID'); + mangledInitData = new Uint8Array(initData); + } - const prefixApi = shaka.polyfill.PatchedMediaKeysWebkit.prefixApi_; - const generateKeyRequestName = prefixApi('generateKeyRequest'); - try { - this.media_[generateKeyRequestName](this.keySystem_, mangledInitData); - } catch (exception) { - if (exception.name != 'InvalidStateError') { - this.generatePromise_ = null; - return Promise.reject(exception); - } + goog.asserts.assert(mangledInitData, + 'init data not set!'); + } catch (exception) { + return Promise.reject(exception); + } - const timer = new shaka.util.Timer(() => { + goog.asserts.assert(this.generatePromise_ == null, + 'generatePromise_ should be null'); + this.generatePromise_ = new shaka.util.PublicPromise(); + + // Because we are hacking media.src in createSession to better emulate + // unprefixed EME's ability to create sessions and license requests without a + // video tag, we can get ourselves into trouble. It seems that sometimes, + // the setting of media.src hasn't been processed by some other thread, and + // GKR can throw an exception. If this occurs, wait 10 ms and try again at + // most once. This situation should only occur when init data is available + // ahead of the 'needkey' event. + + const prefixApi = shaka.polyfill.PatchedMediaKeysWebkit.prefixApi_; + const generateKeyRequestName = prefixApi('generateKeyRequest'); try { this.media_[generateKeyRequestName](this.keySystem_, mangledInitData); - } catch (exception2) { - this.generatePromise_.reject(exception2); - this.generatePromise_ = null; + } catch (exception) { + if (exception.name != 'InvalidStateError') { + this.generatePromise_ = null; + return Promise.reject(exception); + } + + const timer = new shaka.util.Timer(() => { + try { + this.media_[generateKeyRequestName](this.keySystem_, mangledInitData); + } catch (exception2) { + this.generatePromise_.reject(exception2); + this.generatePromise_ = null; + } + }); + + timer.tickAfter(/* seconds= */ 0.01); } - }); - timer.tickAfter(/* seconds= */ 0.01); - } - - return this.generatePromise_; -}; + return this.generatePromise_; + }; /** @@ -781,56 +781,56 @@ shaka.polyfill.PatchedMediaKeysWebkit.MediaKeySession.prototype.generate_ = */ shaka.polyfill.PatchedMediaKeysWebkit.MediaKeySession.prototype.update_ = function(promise, response) { - if (this.updatePromise_) { - // We already have an update in-progress, so defer this one until after the - // old one is resolved. Execute this whether the original one succeeds or - // fails. - this.updatePromise_.then( - this.update_.bind(this, promise, response) - ).catch( - this.update_.bind(this, promise, response) - ); - return; - } + if (this.updatePromise_) { + // We already have an update in-progress, so defer this one until after the + // old one is resolved. Execute this whether the original one succeeds or + // fails. + this.updatePromise_.then( + this.update_.bind(this, promise, response) + ).catch( + this.update_.bind(this, promise, response) + ); + return; + } - this.updatePromise_ = promise; + this.updatePromise_ = promise; - let key; - let keyId; + let key; + let keyId; - if (this.keySystem_ == 'webkit-org.w3.clearkey') { - // The current EME version of clearkey wants a structured JSON response. - // The v0.1b version wants just a raw key. Parse the JSON response and - // extract the key and key ID. - const StringUtils = shaka.util.StringUtils; - const Uint8ArrayUtils = shaka.util.Uint8ArrayUtils; - const licenseString = StringUtils.fromUTF8(response); - const jwkSet = /** @type {JWKSet} */ (JSON.parse(licenseString)); - const kty = jwkSet.keys[0].kty; - if (kty != 'oct') { - // Reject the promise. - const error = new Error('Response is not a valid JSON Web Key Set.'); - this.updatePromise_.reject(error); - this.updatePromise_ = null; - } - key = Uint8ArrayUtils.fromBase64(jwkSet.keys[0].k); - keyId = Uint8ArrayUtils.fromBase64(jwkSet.keys[0].kid); - } else { - // The key ID is not required. - key = new Uint8Array(response); - keyId = null; - } + if (this.keySystem_ == 'webkit-org.w3.clearkey') { + // The current EME version of clearkey wants a structured JSON response. + // The v0.1b version wants just a raw key. Parse the JSON response and + // extract the key and key ID. + const StringUtils = shaka.util.StringUtils; + const Uint8ArrayUtils = shaka.util.Uint8ArrayUtils; + const licenseString = StringUtils.fromUTF8(response); + const jwkSet = /** @type {JWKSet} */ (JSON.parse(licenseString)); + const kty = jwkSet.keys[0].kty; + if (kty != 'oct') { + // Reject the promise. + const error = new Error('Response is not a valid JSON Web Key Set.'); + this.updatePromise_.reject(error); + this.updatePromise_ = null; + } + key = Uint8ArrayUtils.fromBase64(jwkSet.keys[0].k); + keyId = Uint8ArrayUtils.fromBase64(jwkSet.keys[0].kid); + } else { + // The key ID is not required. + key = new Uint8Array(response); + keyId = null; + } - const prefixApi = shaka.polyfill.PatchedMediaKeysWebkit.prefixApi_; - const addKeyName = prefixApi('addKey'); - try { - this.media_[addKeyName](this.keySystem_, key, keyId, this.sessionId); - } catch (exception) { - // Reject the promise. - this.updatePromise_.reject(exception); - this.updatePromise_ = null; - } -}; + const prefixApi = shaka.polyfill.PatchedMediaKeysWebkit.prefixApi_; + const addKeyName = prefixApi('addKey'); + try { + this.media_[addKeyName](this.keySystem_, key, keyId, this.sessionId); + } catch (exception) { + // Reject the promise. + this.updatePromise_.reject(exception); + this.updatePromise_ = null; + } + }; /** @@ -841,89 +841,89 @@ shaka.polyfill.PatchedMediaKeysWebkit.MediaKeySession.prototype.update_ = */ shaka.polyfill.PatchedMediaKeysWebkit.MediaKeySession.prototype .updateKeyStatus_ = function(status) { - this.keyStatuses.setStatus(status); - const event = new shaka.util.FakeEvent('keystatuseschange'); - this.dispatchEvent(event); -}; + this.keyStatuses.setStatus(status); + const event = new shaka.util.FakeEvent('keystatuseschange'); + this.dispatchEvent(event); + }; /** @override */ shaka.polyfill.PatchedMediaKeysWebkit.MediaKeySession.prototype .generateRequest = function(initDataType, initData) { - shaka.log.debug('PatchedMediaKeysWebkit.MediaKeySession.generateRequest'); - return this.generate_(initData, null); -}; + shaka.log.debug('PatchedMediaKeysWebkit.MediaKeySession.generateRequest'); + return this.generate_(initData, null); + }; /** @override */ shaka.polyfill.PatchedMediaKeysWebkit.MediaKeySession.prototype.load = function(sessionId) { - shaka.log.debug('PatchedMediaKeysWebkit.MediaKeySession.load'); - if (this.type_ == 'persistent-license') { - return this.generate_(null, sessionId); - } else { - return Promise.reject(new Error('Not a persistent session.')); - } -}; + shaka.log.debug('PatchedMediaKeysWebkit.MediaKeySession.load'); + if (this.type_ == 'persistent-license') { + return this.generate_(null, sessionId); + } else { + return Promise.reject(new Error('Not a persistent session.')); + } + }; /** @override */ shaka.polyfill.PatchedMediaKeysWebkit.MediaKeySession.prototype.update = function(response) { - shaka.log.debug('PatchedMediaKeysWebkit.MediaKeySession.update', response); - goog.asserts.assert(this.sessionId, 'update without session ID'); + shaka.log.debug('PatchedMediaKeysWebkit.MediaKeySession.update', response); + goog.asserts.assert(this.sessionId, 'update without session ID'); - const nextUpdatePromise = new shaka.util.PublicPromise(); - this.update_(nextUpdatePromise, response); - return nextUpdatePromise; -}; + const nextUpdatePromise = new shaka.util.PublicPromise(); + this.update_(nextUpdatePromise, response); + return nextUpdatePromise; + }; /** @override */ shaka.polyfill.PatchedMediaKeysWebkit.MediaKeySession.prototype.close = function() { - shaka.log.debug('PatchedMediaKeysWebkit.MediaKeySession.close'); + shaka.log.debug('PatchedMediaKeysWebkit.MediaKeySession.close'); - // This will remove a persistent session, but it's also the only way to - // free CDM resources on v0.1b. - if (this.type_ != 'persistent-license') { - // sessionId may reasonably be null if no key request has been generated - // yet. Unprefixed EME will return a rejected promise in this case. - // We will use the same error message that Chrome 41 uses in its EME - // implementation. - if (!this.sessionId) { - this.closed.reject(new Error('The session is not callable.')); + // This will remove a persistent session, but it's also the only way to + // free CDM resources on v0.1b. + if (this.type_ != 'persistent-license') { + // sessionId may reasonably be null if no key request has been generated + // yet. Unprefixed EME will return a rejected promise in this case. + // We will use the same error message that Chrome 41 uses in its EME + // implementation. + if (!this.sessionId) { + this.closed.reject(new Error('The session is not callable.')); + return this.closed; + } + + // This may throw an exception, but we ignore it because we are only using + // it to clean up resources in v0.1b. We still consider the session closed. + // We can't let the exception propagate because MediaKeySession.close() + // should not throw. + const prefixApi = shaka.polyfill.PatchedMediaKeysWebkit.prefixApi_; + const cancelKeyRequestName = prefixApi('cancelKeyRequest'); + try { + this.media_[cancelKeyRequestName](this.keySystem_, this.sessionId); + } catch (exception) {} + } + + // Resolve the 'closed' promise and return it. + this.closed.resolve(); return this.closed; - } - - // This may throw an exception, but we ignore it because we are only using - // it to clean up resources in v0.1b. We still consider the session closed. - // We can't let the exception propagate because MediaKeySession.close() - // should not throw. - const prefixApi = shaka.polyfill.PatchedMediaKeysWebkit.prefixApi_; - const cancelKeyRequestName = prefixApi('cancelKeyRequest'); - try { - this.media_[cancelKeyRequestName](this.keySystem_, this.sessionId); - } catch (exception) {} - } - - // Resolve the 'closed' promise and return it. - this.closed.resolve(); - return this.closed; -}; + }; /** @override */ shaka.polyfill.PatchedMediaKeysWebkit.MediaKeySession.prototype.remove = function() { - shaka.log.debug('PatchedMediaKeysWebkit.MediaKeySession.remove'); + shaka.log.debug('PatchedMediaKeysWebkit.MediaKeySession.remove'); - if (this.type_ != 'persistent-license') { - return Promise.reject(new Error('Not a persistent session.')); - } + if (this.type_ != 'persistent-license') { + return Promise.reject(new Error('Not a persistent session.')); + } - return this.close(); -}; + return this.close(); + }; /** @@ -960,9 +960,9 @@ shaka.polyfill.PatchedMediaKeysWebkit.MediaKeyStatusMap.KEY_ID_; */ shaka.polyfill.PatchedMediaKeysWebkit.MediaKeyStatusMap.prototype.setStatus = function(status) { - this.size = status == undefined ? 0 : 1; - this.status_ = status; -}; + this.size = status == undefined ? 0 : 1; + this.status_ = status; + }; /** @@ -971,43 +971,43 @@ shaka.polyfill.PatchedMediaKeysWebkit.MediaKeyStatusMap.prototype.setStatus = */ shaka.polyfill.PatchedMediaKeysWebkit.MediaKeyStatusMap.prototype.getStatus = function() { - return this.status_; -}; + return this.status_; + }; /** @override */ shaka.polyfill.PatchedMediaKeysWebkit.MediaKeyStatusMap.prototype.forEach = function(fn) { - if (this.status_) { - const fakeKeyId = + if (this.status_) { + const fakeKeyId = shaka.polyfill.PatchedMediaKeysWebkit.MediaKeyStatusMap.KEY_ID_; - fn(this.status_, fakeKeyId); - } -}; + fn(this.status_, fakeKeyId); + } + }; /** @override */ shaka.polyfill.PatchedMediaKeysWebkit.MediaKeyStatusMap.prototype.get = function(keyId) { - if (this.has(keyId)) { - return this.status_; - } - return undefined; -}; + if (this.has(keyId)) { + return this.status_; + } + return undefined; + }; /** @override */ shaka.polyfill.PatchedMediaKeysWebkit.MediaKeyStatusMap.prototype.has = function(keyId) { - const fakeKeyId = + const fakeKeyId = shaka.polyfill.PatchedMediaKeysWebkit.MediaKeyStatusMap.KEY_ID_; - if (this.status_ && + if (this.status_ && shaka.util.Uint8ArrayUtils.equal( new Uint8Array(keyId), new Uint8Array(fakeKeyId))) { - return true; - } - return false; -}; + return true; + } + return false; + }; /** @@ -1016,8 +1016,8 @@ shaka.polyfill.PatchedMediaKeysWebkit.MediaKeyStatusMap.prototype.has = */ shaka.polyfill.PatchedMediaKeysWebkit.MediaKeyStatusMap.prototype .entries = function() { - goog.asserts.assert(false, 'Not used! Provided only for compiler.'); -}; + goog.asserts.assert(false, 'Not used! Provided only for compiler.'); + }; /** @@ -1026,8 +1026,8 @@ shaka.polyfill.PatchedMediaKeysWebkit.MediaKeyStatusMap.prototype */ shaka.polyfill.PatchedMediaKeysWebkit.MediaKeyStatusMap.prototype .keys = function() { - goog.asserts.assert(false, 'Not used! Provided only for compiler.'); -}; + goog.asserts.assert(false, 'Not used! Provided only for compiler.'); + }; /** @@ -1036,8 +1036,8 @@ shaka.polyfill.PatchedMediaKeysWebkit.MediaKeyStatusMap.prototype */ shaka.polyfill.PatchedMediaKeysWebkit.MediaKeyStatusMap.prototype .values = function() { - goog.asserts.assert(false, 'Not used! Provided only for compiler.'); -}; + goog.asserts.assert(false, 'Not used! Provided only for compiler.'); + }; shaka.polyfill.register(shaka.polyfill.PatchedMediaKeysWebkit.install); diff --git a/lib/polyfill/pip_webkit.js b/lib/polyfill/pip_webkit.js index 4e4d879fc..e294ea6e3 100644 --- a/lib/polyfill/pip_webkit.js +++ b/lib/polyfill/pip_webkit.js @@ -134,7 +134,7 @@ shaka.polyfill.PiPWebkit.exitPictureInPicture_ = function() { const PiPWebkit = shaka.polyfill.PiPWebkit; const pipElement = - /** @type {HTMLVideoElement} */(document.pictureInPictureElement); + /** @type {HTMLVideoElement} */(document.pictureInPictureElement); if (pipElement) { // Exit PiP mode. pipElement.webkitSetPresentationMode(PiPWebkit.INLINE_MODE_); diff --git a/lib/routing/walker.js b/lib/routing/walker.js index 69bd72626..0c79ed108 100644 --- a/lib/routing/walker.js +++ b/lib/routing/walker.js @@ -232,7 +232,7 @@ shaka.routing.Walker = class { } goog.asserts.assert(this.waitForWork_ == null, - 'We should not have a promise yet.'); + 'We should not have a promise yet.'); // We have no more work to do. We will wait until new work has been provided // via request route or until we are destroyed. diff --git a/lib/text/mp4_vtt_parser.js b/lib/text/mp4_vtt_parser.js index 819857b17..689ddd4ef 100644 --- a/lib/text/mp4_vtt_parser.js +++ b/lib/text/mp4_vtt_parser.js @@ -245,7 +245,7 @@ shaka.text.Mp4VttParser.prototype.parseMedia = function(data, time) { 'supported!'); return /** @type {!Array.<!shaka.extern.Cue>} */ ( - cues.filter(shaka.util.Functional.isNotNull)); + cues.filter(shaka.util.Functional.isNotNull)); }; @@ -386,10 +386,10 @@ shaka.text.Mp4VttParser.parseVTTC_ = function(data, startTime, endTime) { if (payload) { return shaka.text.Mp4VttParser.assembleCue_(payload, - id, - settings, - startTime, - endTime); + id, + settings, + startTime, + endTime); } else { return null; } @@ -408,10 +408,10 @@ shaka.text.Mp4VttParser.parseVTTC_ = function(data, startTime, endTime) { * @private */ shaka.text.Mp4VttParser.assembleCue_ = function(payload, - id, - settings, - startTime, - endTime) { + id, + settings, + startTime, + endTime) { const cue = new shaka.text.Cue( startTime, endTime, @@ -429,10 +429,10 @@ shaka.text.Mp4VttParser.assembleCue_ = function(payload, while (word) { // TODO: Check WebVTTConfigurationBox for region info. if (!shaka.text.VttTextParser.parseCueSetting(cue, word, - /* VTTRegions */ [])) { + /* VTTRegions */ [])) { shaka.log.warning('VTT parser encountered an invalid VTT setting: ', - word, - ' The setting will be ignored.'); + word, + ' The setting will be ignored.'); } parser.skipWhitespace(); diff --git a/lib/text/simple_text_displayer.js b/lib/text/simple_text_displayer.js index 606989a34..4be9f3cb5 100644 --- a/lib/text/simple_text_displayer.js +++ b/lib/text/simple_text_displayer.js @@ -179,8 +179,8 @@ shaka.text.SimpleTextDisplayer.convertToTextTrackCue_ = function(shakaCue) { const Cue = shaka.text.Cue; /** @type {VTTCue} */ const vttCue = new VTTCue(shakaCue.startTime, - shakaCue.endTime, - shakaCue.payload); + shakaCue.endTime, + shakaCue.payload); // NOTE: positionAlign and lineAlign settings are not supported by Chrome // at the moment, so setting them will have no effect. diff --git a/lib/text/text_engine.js b/lib/text/text_engine.js index cf33c2cf2..cfeaa62a8 100644 --- a/lib/text/text_engine.js +++ b/lib/text/text_engine.js @@ -184,53 +184,53 @@ shaka.text.TextEngine.prototype.getStartTime = function(buffer) { */ shaka.text.TextEngine.prototype.appendBuffer = function(buffer, startTime, endTime) { - goog.asserts.assert(this.parser_, 'The parser should already be initialized'); + goog.asserts.assert(this.parser_, 'The parser should already be initialized'); - // Start the operation asynchronously to avoid blocking the caller. - return Promise.resolve().then(() => { - // Check that TextEngine hasn't been destroyed. - if (!this.parser_ || !this.displayer_) { - return; - } + // Start the operation asynchronously to avoid blocking the caller. + return Promise.resolve().then(() => { + // Check that TextEngine hasn't been destroyed. + if (!this.parser_ || !this.displayer_) { + return; + } - if (startTime == null || endTime == null) { - this.parser_.parseInit(new Uint8Array(buffer)); - return; - } + if (startTime == null || endTime == null) { + this.parser_.parseInit(new Uint8Array(buffer)); + return; + } - /** @type {shaka.extern.TextParser.TimeContext} **/ - const time = { - periodStart: this.timestampOffset_, - segmentStart: startTime, - segmentEnd: endTime, - }; + /** @type {shaka.extern.TextParser.TimeContext} **/ + const time = { + periodStart: this.timestampOffset_, + segmentStart: startTime, + segmentEnd: endTime, + }; - // Parse the buffer and add the new cues. - const allCues = this.parser_.parseMedia(new Uint8Array(buffer), time); - const cuesToAppend = allCues.filter((cue) => { - return cue.startTime >= this.appendWindowStart_ && + // Parse the buffer and add the new cues. + const allCues = this.parser_.parseMedia(new Uint8Array(buffer), time); + const cuesToAppend = allCues.filter((cue) => { + return cue.startTime >= this.appendWindowStart_ && cue.startTime < this.appendWindowEnd_; - }); + }); - this.displayer_.append(cuesToAppend); + this.displayer_.append(cuesToAppend); - // NOTE: We update the buffered range from the start and end times passed - // down from the segment reference, not with the start and end times of the - // parsed cues. This is important because some segments may contain no - // cues, but we must still consider those ranges buffered. - if (this.bufferStart_ == null) { - this.bufferStart_ = Math.max(startTime, this.appendWindowStart_); - } else { - // We already had something in buffer, and we assume we are extending the - // range from the end. - goog.asserts.assert(this.bufferEnd_ != null, - 'There should already be a buffered range end.'); - goog.asserts.assert((startTime - this.bufferEnd_) <= 1, - 'There should not be a gap in text references >1s'); - } - this.bufferEnd_ = Math.min(endTime, this.appendWindowEnd_); - }); -}; + // NOTE: We update the buffered range from the start and end times passed + // down from the segment reference, not with the start and end times of the + // parsed cues. This is important because some segments may contain no + // cues, but we must still consider those ranges buffered. + if (this.bufferStart_ == null) { + this.bufferStart_ = Math.max(startTime, this.appendWindowStart_); + } else { + // We already had something in buffer, and we assume we are extending the + // range from the end. + goog.asserts.assert(this.bufferEnd_ != null, + 'There should already be a buffered range end.'); + goog.asserts.assert((startTime - this.bufferEnd_) <= 1, + 'There should not be a gap in text references >1s'); + } + this.bufferEnd_ = Math.min(endTime, this.appendWindowEnd_); + }); + }; /** @@ -244,10 +244,10 @@ shaka.text.TextEngine.prototype.remove = function(startTime, endTime) { if (this.displayer_ && this.displayer_.remove(startTime, endTime)) { if (this.bufferStart_ == null) { goog.asserts.assert(this.bufferEnd_ == null, - 'end must be null if startTime is null'); + 'end must be null if startTime is null'); } else { goog.asserts.assert(this.bufferEnd_ != null, - 'end must be non-null if startTime is non-null'); + 'end must be non-null if startTime is non-null'); // Update buffered range. if (endTime <= this.bufferStart_ || startTime >= this.bufferEnd_) { @@ -278,8 +278,8 @@ shaka.text.TextEngine.prototype.remove = function(startTime, endTime) { /** @param {number} timestampOffset */ shaka.text.TextEngine.prototype.setTimestampOffset = function(timestampOffset) { - this.timestampOffset_ = timestampOffset; -}; + this.timestampOffset_ = timestampOffset; + }; /** @@ -288,9 +288,9 @@ shaka.text.TextEngine.prototype.setTimestampOffset = */ shaka.text.TextEngine.prototype.setAppendWindow = function(appendWindowStart, appendWindowEnd) { - this.appendWindowStart_ = appendWindowStart; - this.appendWindowEnd_ = appendWindowEnd; -}; + this.appendWindowStart_ = appendWindowStart; + this.appendWindowEnd_ = appendWindowEnd; + }; /** @@ -363,20 +363,20 @@ shaka.text.TextEngine.prototype.appendCues = function(cues) { */ shaka.text.TextEngine.prototype.setSelectedClosedCaptionId = function(id, bufferEndTime) { - this.selectedClosedCaptionId_ = id; + this.selectedClosedCaptionId_ = id; - const captionsMap = this.closedCaptionsMap_.get(id); - if (captionsMap) { - for (const startAndEndTime of captionsMap.keys()) { - /** @type {Array.<!shaka.text.Cue>} */ - let cues = captionsMap.get(startAndEndTime); - if (cues) { - cues = cues.filter((c) => c.endTime <= bufferEndTime); - this.displayer_.append(cues); + const captionsMap = this.closedCaptionsMap_.get(id); + if (captionsMap) { + for (const startAndEndTime of captionsMap.keys()) { + /** @type {Array.<!shaka.text.Cue>} */ + let cues = captionsMap.get(startAndEndTime); + if (cues) { + cues = cues.filter((c) => c.endTime <= bufferEndTime); + this.displayer_.append(cues); + } + } } - } - } -}; + }; /** @@ -467,6 +467,6 @@ shaka.text.TextEngine.prototype.getNumberOfClosedCaptionChannels = function() { */ shaka.text.TextEngine.prototype.getNumberOfClosedCaptionsInChannel = function(channelId) { - const channel = this.closedCaptionsMap_.get(channelId); - return channel ? channel.size : 0; -}; + const channel = this.closedCaptionsMap_.get(channelId); + return channel ? channel.size : 0; + }; diff --git a/lib/text/ttml_text_parser.js b/lib/text/ttml_text_parser.js index db6f0e980..e81bab2e2 100644 --- a/lib/text/ttml_text_parser.js +++ b/lib/text/ttml_text_parser.js @@ -132,13 +132,13 @@ shaka.text.TtmlTextParser.prototype.parseMedia = function(data, time) { for (let i = 0; i < textNodes.length; i++) { const cue = TtmlTextParser.parseCue_(textNodes[i], - time.periodStart, - rateInfo, - metadataElements, - styles, - regionElements, - cueRegions, - whitespaceTrim); + time.periodStart, + rateInfo, + metadataElements, + styles, + regionElements, + cueRegions, + whitespaceTrim); if (cue) { ret.push(cue); } @@ -221,9 +221,9 @@ shaka.text.TtmlTextParser.timeTickFormat_ = /^(\d*(?:\.\d*)?)t$/; */ shaka.text.TtmlTextParser.timeHMSFormat_ = new RegExp(['^(?:(\\d*(?:\\.\\d*)?)h)?', - '(?:(\\d*(?:\\.\\d*)?)m)?', - '(?:(\\d*(?:\\.\\d*)?)s)?', - '(?:(\\d*(?:\\.\\d*)?)ms)?$'].join('')); + '(?:(\\d*(?:\\.\\d*)?)m)?', + '(?:(\\d*(?:\\.\\d*)?)s)?', + '(?:(\\d*(?:\\.\\d*)?)ms)?$'].join('')); /** @@ -274,11 +274,11 @@ shaka.text.TtmlTextParser.getLeafNodes_ = function(element) { childNodes[i].nodeName != 'br' && !isSpanChildOfP) { // Get the leaves the child might contain. goog.asserts.assert(childNodes[i] instanceof Element, - 'Node should be Element!'); + 'Node should be Element!'); const leafChildren = shaka.text.TtmlTextParser.getLeafNodes_( /** @type {Element} */(childNodes[i])); goog.asserts.assert(leafChildren.length > 0, - 'Only a null Element should return no leaves!'); + 'Only a null Element should return no leaves!'); result = result.concat(leafChildren); } } @@ -406,7 +406,7 @@ shaka.text.TtmlTextParser.parseCue_ = function( * @private */ shaka.text.TtmlTextParser.parseCueRegion_ = function(regionElement, styles, - globalExtent) { + globalExtent) { const TtmlTextParser = shaka.text.TtmlTextParser; const region = new shaka.text.CueRegion(); const id = regionElement.getAttribute('xml:id'); @@ -525,7 +525,7 @@ shaka.text.TtmlTextParser.addStyle_ = function( cue.lineAlign = TtmlTextParser.textAlignToLineAlign_[align]; goog.asserts.assert(align.toUpperCase() in Cue.textAlign, - align.toUpperCase() + + align.toUpperCase() + ' Should be in Cue.textAlign values!'); cue.textAlign = Cue.textAlign[align.toUpperCase()]; @@ -535,7 +535,7 @@ shaka.text.TtmlTextParser.addStyle_ = function( cueElement, region, styles, 'displayAlign'); if (displayAlign) { goog.asserts.assert(displayAlign.toUpperCase() in Cue.displayAlign, - displayAlign.toUpperCase() + + displayAlign.toUpperCase() + ' Should be in Cue.displayAlign values!'); cue.displayAlign = Cue.displayAlign[displayAlign.toUpperCase()]; } @@ -586,7 +586,7 @@ shaka.text.TtmlTextParser.addStyle_ = function( cueElement, region, styles, 'fontStyle'); if (fontStyle) { goog.asserts.assert(fontStyle.toUpperCase() in Cue.fontStyle, - fontStyle.toUpperCase() + + fontStyle.toUpperCase() + ' Should be in Cue.fontStyle values!'); cue.fontStyle = Cue.fontStyle[fontStyle.toUpperCase()]; } @@ -640,7 +640,7 @@ shaka.text.TtmlTextParser.addTextDecoration_ = function(cue, decoration) { case 'noUnderline': if (cue.textDecoration.includes(Cue.textDecoration.UNDERLINE)) { shaka.util.ArrayUtils.remove(cue.textDecoration, - Cue.textDecoration.UNDERLINE); + Cue.textDecoration.UNDERLINE); } break; case 'lineThrough': @@ -651,7 +651,7 @@ shaka.text.TtmlTextParser.addTextDecoration_ = function(cue, decoration) { case 'noLineThrough': if (cue.textDecoration.includes(Cue.textDecoration.LINE_THROUGH)) { shaka.util.ArrayUtils.remove(cue.textDecoration, - Cue.textDecoration.LINE_THROUGH); + Cue.textDecoration.LINE_THROUGH); } break; case 'overline': @@ -662,7 +662,7 @@ shaka.text.TtmlTextParser.addTextDecoration_ = function(cue, decoration) { case 'noOverline': if (cue.textDecoration.includes(Cue.textDecoration.OVERLINE)) { shaka.util.ArrayUtils.remove(cue.textDecoration, - Cue.textDecoration.OVERLINE); + Cue.textDecoration.OVERLINE); } break; } diff --git a/lib/text/vtt_text_parser.js b/lib/text/vtt_text_parser.js index a1f5876c4..d55597a7f 100644 --- a/lib/text/vtt_text_parser.js +++ b/lib/text/vtt_text_parser.js @@ -120,7 +120,7 @@ shaka.text.VttTextParser.prototype.parseMedia = function(data, time) { if (cue) { ret.push(cue); } - } + } return ret; }; @@ -149,8 +149,8 @@ shaka.text.VttTextParser.parseRegion_ = function(text) { while (word) { if (!VttTextParser.parseRegionSetting_(region, word)) { shaka.log.warning('VTT parser encountered an invalid VTTRegion setting: ', - word, - ' The setting will be ignored.'); + word, + ' The setting will be ignored.'); } parser.skipWhitespace(); word = parser.readWord(); @@ -220,8 +220,8 @@ shaka.text.VttTextParser.parseCue_ = function(text, timeOffset, regions) { while (word) { if (!VttTextParser.parseCueSetting(cue, word, regions)) { shaka.log.warning('VTT parser encountered an invalid VTT setting: ', - word, - ' The setting will be ignored.'); + word, + ' The setting will be ignored.'); } parser.skipWhitespace(); word = parser.readWord(); @@ -253,7 +253,7 @@ shaka.text.VttTextParser.parseCueSetting = function(cue, word, regions) { cue.size = Number(results[1]); } else if ((results = /^position:([\d.]+)%(?:,(line-left|line-right|center|start|end))?$/ - .exec(word))) { + .exec(word))) { cue.position = Number(results[1]); if (results[2]) { VttTextParser.setPositionAlign_(cue, results[2]); @@ -284,12 +284,12 @@ shaka.text.VttTextParser.getRegionById_ = function(regions, id) { }); if (!regionsWithId.length) { shaka.log.warning('VTT parser could not find a region with id: ', - id, - ' The region will be ignored.'); + id, + ' The region will be ignored.'); return null; } goog.asserts.assert(regionsWithId.length == 1, - 'VTTRegion ids should be unique!'); + 'VTTRegion ids should be unique!'); return regionsWithId[0]; }; @@ -313,11 +313,11 @@ shaka.text.VttTextParser.parseRegionSetting_ = function(region, word) { region.height = Number(results[1]); region.heightUnits = shaka.text.CueRegion.units.LINES; } else if ((results = /^regionanchor=(\d{1,2}|100)%,(\d{1,2}|100)%$/ - .exec(word))) { + .exec(word))) { region.regionAnchorX = Number(results[1]); region.regionAnchorY = Number(results[2]); } else if ((results = /^viewportanchor=(\d{1,2}|100)%,(\d{1,2}|100)%$/ - .exec(word))) { + .exec(word))) { region.viewportAnchorX = Number(results[1]); region.viewportAnchorY = Number(results[2]); } else if ((results = /^scroll=up$/.exec(word))) { @@ -341,7 +341,7 @@ shaka.text.VttTextParser.setTextAlign_ = function(cue, align) { cue.textAlign = Cue.textAlign.CENTER; } else { goog.asserts.assert(align.toUpperCase() in Cue.textAlign, - align.toUpperCase() + + align.toUpperCase() + ' Should be in Cue.textAlign values!'); cue.textAlign = Cue.textAlign[align.toUpperCase()]; @@ -389,32 +389,32 @@ shaka.text.VttTextParser.setVerticalWritingMode_ = function(cue, value) { */ shaka.text.VttTextParser.parsedLineValueAndInterpretation_ = function(cue, word) { - const Cue = shaka.text.Cue; - let results = null; - if ((results = /^line:([\d.]+)%(?:,(start|end|center))?$/.exec(word))) { - cue.lineInterpretation = Cue.lineInterpretation.PERCENTAGE; - cue.line = Number(results[1]); - if (results[2]) { - goog.asserts.assert(results[2].toUpperCase() in Cue.lineAlign, - results[2].toUpperCase() + + const Cue = shaka.text.Cue; + let results = null; + if ((results = /^line:([\d.]+)%(?:,(start|end|center))?$/.exec(word))) { + cue.lineInterpretation = Cue.lineInterpretation.PERCENTAGE; + cue.line = Number(results[1]); + if (results[2]) { + goog.asserts.assert(results[2].toUpperCase() in Cue.lineAlign, + results[2].toUpperCase() + ' Should be in Cue.lineAlign values!'); - cue.lineAlign = Cue.lineAlign[results[2].toUpperCase()]; - } - } else if ((results = /^line:(-?\d+)(?:,(start|end|center))?$/.exec(word))) { - cue.lineInterpretation = Cue.lineInterpretation.LINE_NUMBER; - cue.line = Number(results[1]); - if (results[2]) { - goog.asserts.assert(results[2].toUpperCase() in Cue.lineAlign, - results[2].toUpperCase() + + cue.lineAlign = Cue.lineAlign[results[2].toUpperCase()]; + } + } else if ((results = /^line:(-?\d+)(?:,(start|end|center))?$/.exec(word))) { + cue.lineInterpretation = Cue.lineInterpretation.LINE_NUMBER; + cue.line = Number(results[1]); + if (results[2]) { + goog.asserts.assert(results[2].toUpperCase() in Cue.lineAlign, + results[2].toUpperCase() + ' Should be in Cue.lineAlign values!'); - cue.lineAlign = Cue.lineAlign[results[2].toUpperCase()]; - } - } else { - return false; - } + cue.lineAlign = Cue.lineAlign[results[2].toUpperCase()]; + } + } else { + return false; + } - return true; -}; + return true; + }; /** diff --git a/lib/util/config_utils.js b/lib/util/config_utils.js index 765aa40a1..726607c70 100644 --- a/lib/util/config_utils.js +++ b/lib/util/config_utils.js @@ -35,68 +35,68 @@ goog.require('shaka.log'); */ shaka.util.ConfigUtils.mergeConfigObjects = function(destination, source, template, overrides, path) { - goog.asserts.assert(destination, 'Destination config must not be null!'); + goog.asserts.assert(destination, 'Destination config must not be null!'); - /** + /** * @type {boolean} * If true, don't validate the keys in the next level. */ - const ignoreKeys = path in overrides; + const ignoreKeys = path in overrides; - let isValid = true; + let isValid = true; - for (const k in source) { - const subPath = path + '.' + k; - const subTemplate = ignoreKeys ? overrides[path] : template[k]; + for (const k in source) { + const subPath = path + '.' + k; + const subTemplate = ignoreKeys ? overrides[path] : template[k]; - // The order of these checks is important. - if (!ignoreKeys && !(k in template)) { - shaka.log.error('Invalid config, unrecognized key ' + subPath); - isValid = false; - } else if (source[k] === undefined) { - // An explicit 'undefined' value causes the key to be deleted from the - // destination config and replaced with a default from the template if - // possible. - if (subTemplate === undefined || ignoreKeys) { - // There is nothing in the template, so delete. - delete destination[k]; - } else { - // There is something in the template, so go back to that. - destination[k] = shaka.util.ObjectUtils.cloneObject(subTemplate); - } - } else if (subTemplate.constructor == Object && + // The order of these checks is important. + if (!ignoreKeys && !(k in template)) { + shaka.log.error('Invalid config, unrecognized key ' + subPath); + isValid = false; + } else if (source[k] === undefined) { + // An explicit 'undefined' value causes the key to be deleted from the + // destination config and replaced with a default from the template if + // possible. + if (subTemplate === undefined || ignoreKeys) { + // There is nothing in the template, so delete. + delete destination[k]; + } else { + // There is something in the template, so go back to that. + destination[k] = shaka.util.ObjectUtils.cloneObject(subTemplate); + } + } else if (subTemplate.constructor == Object && source[k] && source[k].constructor == Object) { - // These are plain Objects with no other constructor. + // These are plain Objects with no other constructor. - if (!destination[k]) { - // Initialize the destination with the template so that normal merging - // and type-checking can happen. - destination[k] = shaka.util.ObjectUtils.cloneObject(subTemplate); - } + if (!destination[k]) { + // Initialize the destination with the template so that normal merging + // and type-checking can happen. + destination[k] = shaka.util.ObjectUtils.cloneObject(subTemplate); + } - const subMergeValid = shaka.util.ConfigUtils.mergeConfigObjects( - destination[k], source[k], subTemplate, overrides, subPath); - isValid = isValid && subMergeValid; - } else if (typeof source[k] != typeof subTemplate || + const subMergeValid = shaka.util.ConfigUtils.mergeConfigObjects( + destination[k], source[k], subTemplate, overrides, subPath); + isValid = isValid && subMergeValid; + } else if (typeof source[k] != typeof subTemplate || source[k] == null || source[k].constructor != subTemplate.constructor) { - // The source is the wrong type. This check allows objects to be nulled, - // but does not allow null for any non-object fields. - shaka.log.error('Invalid config, wrong type for ' + subPath); - isValid = false; - } else if (typeof template[k] == 'function' && + // The source is the wrong type. This check allows objects to be nulled, + // but does not allow null for any non-object fields. + shaka.log.error('Invalid config, wrong type for ' + subPath); + isValid = false; + } else if (typeof template[k] == 'function' && template[k].length != source[k].length) { - shaka.log.warning( - 'Invalid config, wrong number of arguments for ' + subPath); - destination[k] = source[k]; - } else { - destination[k] = source[k]; - } - } + shaka.log.warning( + 'Invalid config, wrong number of arguments for ' + subPath); + destination[k] = source[k]; + } else { + destination[k] = source[k]; + } + } - return isValid; -}; + return isValid; + }; /** diff --git a/lib/util/event_manager.js b/lib/util/event_manager.js index e14cd812f..f81040475 100644 --- a/lib/util/event_manager.js +++ b/lib/util/event_manager.js @@ -80,15 +80,15 @@ shaka.util.EventManager.prototype.listen = function(target, type, listener) { */ shaka.util.EventManager.prototype.listenOnce = function(target, type, listener) { - // Install a shim listener that will stop listening after the first event. - const shim = (event) => { - // Stop listening to this event. - this.unlisten(target, type, shim); - // Call the original listener. - listener(event); - }; - this.listen(target, type, shim); -}; + // Install a shim listener that will stop listening after the first event. + const shim = (event) => { + // Stop listening to this event. + this.unlisten(target, type, shim); + // Call the original listener. + listener(event); + }; + this.listen(target, type, shim); + }; /** diff --git a/lib/util/fake_event_target.js b/lib/util/fake_event_target.js index 37370595d..258523da4 100644 --- a/lib/util/fake_event_target.js +++ b/lib/util/fake_event_target.js @@ -67,8 +67,8 @@ shaka.util.FakeEventTarget.ListenerType; */ shaka.util.FakeEventTarget.prototype.addEventListener = function(type, listener, options) { - this.listeners_.push(type, listener); -}; + this.listeners_.push(type, listener); + }; /** @@ -83,8 +83,8 @@ shaka.util.FakeEventTarget.prototype.addEventListener = */ shaka.util.FakeEventTarget.prototype.removeEventListener = function(type, listener, options) { - this.listeners_.remove(type, listener); -}; + this.listeners_.remove(type, listener); + }; /** @@ -99,7 +99,7 @@ shaka.util.FakeEventTarget.prototype.dispatchEvent = function(event) { // In many browsers, it is complex to overwrite properties of actual Events. // Here we expect only to dispatch FakeEvents, which are simpler. goog.asserts.assert(event instanceof shaka.util.FakeEvent, - 'FakeEventTarget can only dispatch FakeEvents!'); + 'FakeEventTarget can only dispatch FakeEvents!'); const listeners = this.listeners_.get(event.type) || []; diff --git a/lib/util/manifest_filter.js b/lib/util/manifest_filter.js index 938b51010..ac56ac2b8 100644 --- a/lib/util/manifest_filter.js +++ b/lib/util/manifest_filter.js @@ -92,7 +92,7 @@ shaka.util.ManifestFilter = class { */ static filterByCommonCodecs(manifest) { goog.asserts.assert(manifest.periods.length > 0, - 'There should be at least be one period'); + 'There should be at least be one period'); const ManifestFilter = shaka.util.ManifestFilter; diff --git a/lib/util/manifest_parser_utils.js b/lib/util/manifest_parser_utils.js index 3008cde65..84b4c8074 100644 --- a/lib/util/manifest_parser_utils.js +++ b/lib/util/manifest_parser_utils.js @@ -45,9 +45,9 @@ shaka.util.ManifestParserUtils.resolveUris = function(baseUris, relativeUris) { // Resolve each URI relative to each base URI, creating an Array of Arrays. // Then flatten the Arrays into a single Array. return baseUris.map((uri) => new goog.Uri(uri)) - .map((base) => relativeAsGoog.map(base.resolve.bind(base))) - .reduce(Functional.collapseArrays, []) - .map((uri) => uri.toString()); + .map((base) => relativeAsGoog.map(base.resolve.bind(base))) + .reduce(Functional.collapseArrays, []) + .map((uri) => uri.toString()); }; diff --git a/lib/util/mime_utils.js b/lib/util/mime_utils.js index 0d874df6b..3cc97b321 100644 --- a/lib/util/mime_utils.js +++ b/lib/util/mime_utils.js @@ -110,12 +110,12 @@ shaka.util.MimeUtils = class { * @private */ shaka.util.MimeUtils.EXTENDED_MIME_PARAMETERS_ = new Map() - .set('codecs', 'codecs') - .set('frameRate', 'framerate') // Ours is camelCase, theirs is lowercase. - .set('bandwidth', 'bitrate') // They are in the same units: bits/sec. - .set('width', 'width') - .set('height', 'height') - .set('channelsCount', 'channels'); + .set('codecs', 'codecs') + .set('frameRate', 'framerate') // Ours is camelCase, theirs is lowercase. + .set('bandwidth', 'bitrate') // They are in the same units: bits/sec. + .set('width', 'width') + .set('height', 'height') + .set('channelsCount', 'channels'); /** diff --git a/lib/util/mp4_parser.js b/lib/util/mp4_parser.js index d58e198d9..aa1d6fb3e 100644 --- a/lib/util/mp4_parser.js +++ b/lib/util/mp4_parser.js @@ -138,73 +138,73 @@ shaka.util.Mp4Parser.prototype.parse = function(data, partialOkay) { */ shaka.util.Mp4Parser.prototype.parseNext = function(absStart, reader, partialOkay) { - const start = reader.getPosition(); + const start = reader.getPosition(); - let size = reader.readUint32(); - const type = reader.readUint32(); - const name = shaka.util.Mp4Parser.typeToString(type); - shaka.log.v2('Parsing MP4 box', name); + let size = reader.readUint32(); + const type = reader.readUint32(); + const name = shaka.util.Mp4Parser.typeToString(type); + shaka.log.v2('Parsing MP4 box', name); - switch (size) { - case 0: - size = reader.getLength() - start; - break; - case 1: - size = reader.readUint64(); - break; - } + switch (size) { + case 0: + size = reader.getLength() - start; + break; + case 1: + size = reader.readUint64(); + break; + } - const boxDefinition = this.boxDefinitions_[type]; + const boxDefinition = this.boxDefinitions_[type]; - if (boxDefinition) { - let version = null; - let flags = null; + if (boxDefinition) { + let version = null; + let flags = null; - if (this.headers_[type] == shaka.util.Mp4Parser.BoxType_.FULL_BOX) { - const versionAndFlags = reader.readUint32(); - version = versionAndFlags >>> 24; - flags = versionAndFlags & 0xFFFFFF; - } + if (this.headers_[type] == shaka.util.Mp4Parser.BoxType_.FULL_BOX) { + const versionAndFlags = reader.readUint32(); + version = versionAndFlags >>> 24; + flags = versionAndFlags & 0xFFFFFF; + } - // Read the whole payload so that the current level can be safely read - // regardless of how the payload is parsed. - let end = start + size; - if (partialOkay && end > reader.getLength()) { - // For partial reads, truncate the payload if we must. - end = reader.getLength(); - } - const payloadSize = end - reader.getPosition(); - const payload = + // Read the whole payload so that the current level can be safely read + // regardless of how the payload is parsed. + let end = start + size; + if (partialOkay && end > reader.getLength()) { + // For partial reads, truncate the payload if we must. + end = reader.getLength(); + } + const payloadSize = end - reader.getPosition(); + const payload = (payloadSize > 0) ? reader.readBytes(payloadSize) : new Uint8Array(0); - const payloadReader = new shaka.util.DataViewReader( - new DataView(payload.buffer, payload.byteOffset, payload.byteLength), - shaka.util.DataViewReader.Endianness.BIG_ENDIAN); + const payloadReader = new shaka.util.DataViewReader( + new DataView(payload.buffer, payload.byteOffset, payload.byteLength), + shaka.util.DataViewReader.Endianness.BIG_ENDIAN); - /** @type {shaka.extern.ParsedBox} */ - const box = { - parser: this, - partialOkay: partialOkay || false, - version: version, - flags: flags, - reader: payloadReader, - size: size, - start: start + absStart, + /** @type {shaka.extern.ParsedBox} */ + const box = { + parser: this, + partialOkay: partialOkay || false, + version: version, + flags: flags, + reader: payloadReader, + size: size, + start: start + absStart, + }; + + boxDefinition(box); + } else { + // Move the read head to be at the end of the box. + // If the box is longer than the remaining parts of the file, e.g. the + // mp4 is improperly formatted, or this was a partial range request that + // ended in the middle of a box, just skip to the end. + const skipLength = Math.min( + start + size - reader.getPosition(), + reader.getLength() - reader.getPosition()); + reader.skip(skipLength); + } }; - boxDefinition(box); - } else { - // Move the read head to be at the end of the box. - // If the box is longer than the remaining parts of the file, e.g. the - // mp4 is improperly formatted, or this was a partial range request that - // ended in the middle of a box, just skip to the end. - const skipLength = Math.min( - start + size - reader.getPosition(), - reader.getLength() - reader.getPosition()); - reader.skip(skipLength); - } -}; - /** * A callback that tells the Mp4 parser to treat the body of a box as a series @@ -231,8 +231,8 @@ shaka.util.Mp4Parser.children = function(box) { */ shaka.util.Mp4Parser.sampleDescription = function(box) { for (let count = box.reader.readUint32(); - count > 0 && !box.parser.done_; - count -= 1) { + count > 0 && !box.parser.done_; + count -= 1) { box.parser.parseNext(box.start, box.reader, box.partialOkay); } }; diff --git a/lib/util/object_utils.js b/lib/util/object_utils.js index db1fbaf89..9cb2d00d0 100644 --- a/lib/util/object_utils.js +++ b/lib/util/object_utils.js @@ -19,7 +19,7 @@ goog.provide('shaka.util.ObjectUtils'); shaka.util.ObjectUtils = class { - /** + /** * Performs a deep clone of the given simple object. This does not copy * prototypes, custom properties (e.g. read-only), or multiple references to * the same object. If the caller needs these fields, it will need to set them diff --git a/lib/util/platform.js b/lib/util/platform.js index d4355b081..1929f34f3 100644 --- a/lib/util/platform.js +++ b/lib/util/platform.js @@ -182,11 +182,11 @@ shaka.util.Platform = class { } Platform.cachedMediaElement_ = /** @type {HTMLMediaElement} */( - document.querySelector('video') || document.querySelector('audio')); + document.querySelector('video') || document.querySelector('audio')); if (!Platform.cachedMediaElement_) { Platform.cachedMediaElement_ = /** @type {!HTMLMediaElement} */( - document.createElement('video')); + document.createElement('video')); } Platform.cacheExpirationTimer_.tickAfter(/* seconds= */ 1); diff --git a/lib/util/player_configuration.js b/lib/util/player_configuration.js index 55e542149..05835dc4f 100644 --- a/lib/util/player_configuration.js +++ b/lib/util/player_configuration.js @@ -146,9 +146,9 @@ shaka.util.PlayerConfiguration = class { // to the function as it would be a no-op. progressCallback: (content, progress) => { shaka.log.v2('Offline operation on', - content.originalManifestUri, - 'progress at', - progress); + content.originalManifestUri, + 'progress at', + progress); }, // By default we use persistent licenses as forces errors to surface if diff --git a/lib/util/stream_utils.js b/lib/util/stream_utils.js index 14308d8de..06c9859b7 100644 --- a/lib/util/stream_utils.js +++ b/lib/util/stream_utils.js @@ -57,27 +57,27 @@ shaka.util.StreamUtils.meetsRestrictions = function( // the math, so make sure they are there first. if (video && video.width && video.height) { if (!inRange(video.width, - restrictions.minWidth, - Math.min(restrictions.maxWidth, maxHwRes.width))) { + restrictions.minWidth, + Math.min(restrictions.maxWidth, maxHwRes.width))) { return false; } if (!inRange(video.height, - restrictions.minHeight, - Math.min(restrictions.maxHeight, maxHwRes.height))) { + restrictions.minHeight, + Math.min(restrictions.maxHeight, maxHwRes.height))) { return false; } if (!inRange(video.width * video.height, - restrictions.minPixels, - restrictions.maxPixels)) { + restrictions.minPixels, + restrictions.maxPixels)) { return false; } } if (!inRange(variant.bandwidth, - restrictions.minBandwidth, - restrictions.maxBandwidth)) { + restrictions.minBandwidth, + restrictions.maxBandwidth)) { return false; } @@ -93,20 +93,20 @@ shaka.util.StreamUtils.meetsRestrictions = function( */ shaka.util.StreamUtils.applyRestrictions = function(variants, restrictions, maxHwRes) { - let tracksChanged = false; + let tracksChanged = false; - variants.forEach((variant) => { - const originalAllowed = variant.allowedByApplication; - variant.allowedByApplication = shaka.util.StreamUtils.meetsRestrictions( - variant, restrictions, maxHwRes); + variants.forEach((variant) => { + const originalAllowed = variant.allowedByApplication; + variant.allowedByApplication = shaka.util.StreamUtils.meetsRestrictions( + variant, restrictions, maxHwRes); - if (originalAllowed != variant.allowedByApplication) { - tracksChanged = true; - } - }); + if (originalAllowed != variant.allowedByApplication) { + tracksChanged = true; + } + }); - return tracksChanged; -}; + return tracksChanged; + }; /** @@ -123,12 +123,12 @@ shaka.util.StreamUtils.filterNewPeriod = function( if (activeAudio) { goog.asserts.assert(StreamUtils.isAudio(activeAudio), - 'Audio streams must have the audio type.'); + 'Audio streams must have the audio type.'); } if (activeVideo) { goog.asserts.assert(StreamUtils.isVideo(activeVideo), - 'Video streams must have the video type.'); + 'Video streams must have the video type.'); } // Filter variants. @@ -136,7 +136,7 @@ shaka.util.StreamUtils.filterNewPeriod = function( if (drmEngine && drmEngine.initialized()) { if (!drmEngine.supportsVariant(variant)) { shaka.log.debug('Dropping variant - not compatible with key system', - variant); + variant); return false; } } @@ -146,23 +146,23 @@ shaka.util.StreamUtils.filterNewPeriod = function( if (audio && !shaka.media.MediaSourceEngine.isStreamSupported(audio)) { shaka.log.debug('Dropping variant - audio not compatible with platform', - StreamUtils.getStreamSummaryString_(audio)); + StreamUtils.getStreamSummaryString_(audio)); return false; } if (video && !shaka.media.MediaSourceEngine.isStreamSupported(video)) { shaka.log.debug('Dropping variant - video not compatible with platform', - StreamUtils.getStreamSummaryString_(video)); + StreamUtils.getStreamSummaryString_(video)); return false; } if (audio && activeAudio) { if (!StreamUtils.areStreamsCompatible_(audio, activeAudio)) { shaka.log.debug('Droping variant - not compatible with active audio', - 'active audio', - StreamUtils.getStreamSummaryString_(activeAudio), - 'variant.audio', - StreamUtils.getStreamSummaryString_(audio)); + 'active audio', + StreamUtils.getStreamSummaryString_(activeAudio), + 'variant.audio', + StreamUtils.getStreamSummaryString_(audio)); return false; } } @@ -170,10 +170,10 @@ shaka.util.StreamUtils.filterNewPeriod = function( if (video && activeVideo) { if (!StreamUtils.areStreamsCompatible_(video, activeVideo)) { shaka.log.debug('Droping variant - not compatible with active video', - 'active video', - StreamUtils.getStreamSummaryString_(activeVideo), - 'variant.video', - StreamUtils.getStreamSummaryString_(video)); + 'active video', + StreamUtils.getStreamSummaryString_(activeVideo), + 'variant.video', + StreamUtils.getStreamSummaryString_(video)); return false; } } @@ -635,10 +635,10 @@ shaka.util.StreamUtils.filterStreamsByLanguageAndRole = function( */ shaka.util.StreamUtils.filterTextStreamsByRole_ = function(textStreams, preferredRole) { - return textStreams.filter((stream) => { - return stream.roles.includes(preferredRole); - }); -}; + return textStreams.filter((stream) => { + return stream.roles.includes(preferredRole); + }); + }; /** diff --git a/lib/util/uint8array_utils.js b/lib/util/uint8array_utils.js index b59107aea..899f9c147 100644 --- a/lib/util/uint8array_utils.js +++ b/lib/util/uint8array_utils.js @@ -35,8 +35,8 @@ goog.require('shaka.util.StringUtils'); */ shaka.util.Uint8ArrayUtils.toStandardBase64 = function(u8Arr) { - const bytes = shaka.util.StringUtils.fromCharCode(u8Arr); - return btoa(bytes); + const bytes = shaka.util.StringUtils.fromCharCode(u8Arr); + return btoa(bytes); }; /** @@ -51,7 +51,7 @@ shaka.util.Uint8ArrayUtils.toStandardBase64 = function(u8Arr) { shaka.util.Uint8ArrayUtils.toBase64 = function(arr, padding) { padding = (padding == undefined) ? true : padding; const base64 = shaka.util.Uint8ArrayUtils.toStandardBase64(arr) - .replace(/\+/g, '-').replace(/\//g, '_'); + .replace(/\+/g, '-').replace(/\//g, '_'); return padding ? base64 : base64.replace(/[=]*$/, ''); }; diff --git a/test/cast/cast_receiver_integration.js b/test/cast/cast_receiver_integration.js index ff49826e5..c5809af6d 100644 --- a/test/cast/cast_receiver_integration.js +++ b/test/cast/cast_receiver_integration.js @@ -77,15 +77,15 @@ describe('CastReceiver', () => { return () => check(undefined); } - /** + /** * Before running the test, check if this is Chrome or Chromecast, and if * Widevine is supported. * @param {function(function()=)} test * @return {function(function())} */ - function checkAndRunWithDrm(test) { - return checkAndRun(test, /* checkKeySystems */ true); - } + function checkAndRunWithDrm(test) { + return checkAndRun(test, /* checkKeySystems */ true); + } beforeAll((done) => { const supportTest = shaka.media.DrmEngine.probeSupport() @@ -107,7 +107,7 @@ describe('CastReceiver', () => { // Since we can't write to window.navigator or navigator.userAgent, we use // Object.defineProperty. Object.defineProperty(window['navigator'], - 'userAgent', {value: 'CrKey', configurable: true}); + 'userAgent', {value: 'CrKey', configurable: true}); shaka.net.NetworkingEngine.registerScheme('test', shaka.test.TestScheme); shaka.media.ManifestParser.registerParserByMime( @@ -182,7 +182,7 @@ describe('CastReceiver', () => { if (originalUserAgent) { window['cast'] = originalCast; Object.defineProperty(window['navigator'], - 'userAgent', {value: originalUserAgent}); + 'userAgent', {value: originalUserAgent}); } }); diff --git a/test/cast/cast_receiver_unit.js b/test/cast/cast_receiver_unit.js index db37ce18e..d20cdfb30 100644 --- a/test/cast/cast_receiver_unit.js +++ b/test/cast/cast_receiver_unit.js @@ -50,19 +50,19 @@ describe('CastReceiver', () => { * @return {function(function())} */ function checkAndRun(test) { - const check = function(done) { - if (!isChromecast && !isChrome) { - pending( - 'Skipping CastReceiver tests for non-Chrome and non-Chromecast'); - } else { - test(done); - } - }; - // Account for tests with a done argument, and tests without. - if (test.length == 1) { - return (done) => check(done); - } - return () => check(undefined); + const check = function(done) { + if (!isChromecast && !isChrome) { + pending( + 'Skipping CastReceiver tests for non-Chrome and non-Chromecast'); + } else { + test(done); + } + }; + // Account for tests with a done argument, and tests without. + if (test.length == 1) { + return (done) => check(done); + } + return () => check(undefined); } beforeAll(() => { @@ -86,7 +86,7 @@ describe('CastReceiver', () => { // Since we can't write to window.navigator or navigator.userAgent, we use // Object.defineProperty. Object.defineProperty(window['navigator'], - 'userAgent', {value: 'CrKey', configurable: true}); + 'userAgent', {value: 'CrKey', configurable: true}); }); beforeEach(checkAndRun(() => { @@ -122,7 +122,7 @@ describe('CastReceiver', () => { if (originalUserAgent) { window['cast'] = originalCast; Object.defineProperty(window['navigator'], - 'userAgent', {value: originalUserAgent}); + 'userAgent', {value: originalUserAgent}); } }); @@ -773,18 +773,18 @@ describe('CastReceiver', () => { return; } expect(mockGenericMessageBus.messages[0]).toEqual( - { - requestId: 0, - type: 'MEDIA_STATUS', - status: [jasmine.objectContaining({ - media: { - contentId: expectedUri, - streamType: 'BUFFERED', - duration: expectedDuration, - contentType: '', - }, - })], - } + { + requestId: 0, + type: 'MEDIA_STATUS', + status: [jasmine.objectContaining({ + media: { + contentId: expectedUri, + streamType: 'BUFFERED', + duration: expectedDuration, + contentType: '', + }, + })], + } ); mockGenericMessageBus.messages.shift(); } diff --git a/test/cast/cast_sender_unit.js b/test/cast/cast_sender_unit.js index e3de492af..4129b1d7e 100644 --- a/test/cast/cast_sender_unit.js +++ b/test/cast/cast_sender_unit.js @@ -50,7 +50,7 @@ describe('CastSender', () => { onRemoteEvent = jasmine.createSpy('onRemoteEvent'); onResumeLocal = jasmine.createSpy('onResumeLocal'); onInitStateRequired = jasmine.createSpy('onInitStateRequired') - .and.returnValue(fakeInitState); + .and.returnValue(fakeInitState); mockCastApi = createMockCastApi(); // We're using quotes to access window.chrome because the compiler diff --git a/test/cast/cast_utils_unit.js b/test/cast/cast_utils_unit.js index e709a7381..5d87b5a62 100644 --- a/test/cast/cast_utils_unit.js +++ b/test/cast/cast_utils_unit.js @@ -43,7 +43,7 @@ describe('CastUtils', () => { ]; const castMembers = CastUtils.PlayerVoidMethods - .concat(CastUtils.PlayerPromiseMethods); + .concat(CastUtils.PlayerPromiseMethods); for (const name in CastUtils.PlayerGetterMethods) { castMembers.push(name); } @@ -95,7 +95,7 @@ describe('CastUtils', () => { it('transfers real Events', () => { // new Event() is not usable on IE11: const event = - /** @type {!CustomEvent} */ (document.createEvent('CustomEvent')); + /** @type {!CustomEvent} */ (document.createEvent('CustomEvent')); event.initCustomEvent('myEventType', false, false, null); // Properties that can definitely be transferred. diff --git a/test/dash/dash_parser_content_protection_unit.js b/test/dash/dash_parser_content_protection_unit.js index fdd641e18..645ed03f8 100644 --- a/test/dash/dash_parser_content_protection_unit.js +++ b/test/dash/dash_parser_content_protection_unit.js @@ -165,7 +165,7 @@ describe('DashParser ContentProtection', () => { it(name, async () => { const adaptationSetLines = uuids.map((uri) => { return sprintf('<ContentProtection schemeIdUri="urn:uuid:%s" />', - uri); + uri); }); const source = buildManifestText(adaptationSetLines, [], []); const drmInfos = keySystems.map((keySystem) => { @@ -338,7 +338,7 @@ describe('DashParser ContentProtection', () => { buildDrmInfo('com.adobe.primetime'), ]))); await testDashParser(source, expected, /* callback */ undefined, - /* ignoreDrmInfo */ true); + /* ignoreDrmInfo */ true); }); it('parses key IDs when ignoreDrmInfo flag is set', async () => { @@ -365,7 +365,7 @@ describe('DashParser ContentProtection', () => { buildDrmInfo('com.adobe.primetime', keyIds), ]); await testDashParser(source, expected, /* callback */ undefined, - /* ignoreDrmInfo */ true); + /* ignoreDrmInfo */ true); }); it('inherits PSSH from generic CENC into all key systems', async () => { @@ -502,12 +502,12 @@ describe('DashParser ContentProtection', () => { ], [], []); const expected = buildExpectedManifest([ buildDrmInfo('', // placeholder: only unrecognized schemes found - [ + [ // Representation 1 key ID - 'deadbeeffeedbaadf00d000008675309', - // Representation 2 key ID - 'deadbeeffeedbaadf00d000008675309', - ]), + 'deadbeeffeedbaadf00d000008675309', + // Representation 2 key ID + 'deadbeeffeedbaadf00d000008675309', + ]), ]); await testDashParser(source, expected); }); @@ -761,7 +761,7 @@ describe('In-manifest PlayReady and Widevine', () => { expect(actual).toEqual(expected); }); - it('ms:laurl without license url', () => { + it('ms:laurl without license url', () => { const input = { init: null, keyId: null, @@ -777,7 +777,7 @@ describe('In-manifest PlayReady and Widevine', () => { expect(actual).toEqual(expected); }); - it('no ms:laurl node', () => { + it('no ms:laurl node', () => { const input = { init: null, keyId: null, @@ -818,10 +818,10 @@ describe('In-manifest PlayReady and Widevine', () => { const encodedPrObject = shaka.util.Uint8ArrayUtils.toBase64(new Uint8Array(prBytes.buffer)); const input = { - init: null, - keyId: null, - schemeUri: '', - node: + init: null, + keyId: null, + schemeUri: '', + node: strToXml([ '<test xmlns:mspr="urn:microsoft:playready">', ' <mspr:pro>' + encodedPrObject + '</mspr:pro>', diff --git a/test/dash/dash_parser_live_unit.js b/test/dash/dash_parser_live_unit.js index 1d954acd9..86565655d 100644 --- a/test/dash/dash_parser_live_unit.js +++ b/test/dash/dash_parser_live_unit.js @@ -631,7 +631,7 @@ describe('DashParser Live', () => { fakeNetEngine.request.and.callFake((type, request) => { expect(type).toBe(manifestRequest); expect(request.uris).toEqual( - ['http://foobar', 'http://foobar2', 'dummy://foo/foobar3']); + ['http://foobar', 'http://foobar2', 'dummy://foo/foobar3']); const data = shaka.util.StringUtils.toUTF8(manifestText); return shaka.util.AbortableOperation.completed( {uri: request.uris[0], data: data, headers: {}}); diff --git a/test/dash/dash_parser_manifest_unit.js b/test/dash/dash_parser_manifest_unit.js index 4b6f95ec4..fbf0b6144 100644 --- a/test/dash/dash_parser_manifest_unit.js +++ b/test/dash/dash_parser_manifest_unit.js @@ -314,51 +314,51 @@ describe('DashParser Manifest', () => { it('correctly parses closed captions with channels and languages', async () => { - const source = [ - '<MPD minBufferTime="PT75S">', - ' <Period id="1" duration="PT30S">', - ' <AdaptationSet mimeType="video/mp4" lang="en" group="1">', - ' <Accessibility schemeIdUri="urn:scte:dash:cc:cea-608:2015"', - ' value="CC1=eng;CC3=swe"/>', - ' <Representation bandwidth="200">', - ' <SegmentTemplate media="1.mp4" duration="1" />', - ' </Representation>', - ' </AdaptationSet>', - ' <AdaptationSet mimeType="video/mp4" lang="en" group="1">', - ' <Accessibility schemeIdUri="urn:scte:dash:cc:cea-608:2015"', - ' value="CC1=lang:eng;CC3=lang:swe"/>', - ' <Representation bandwidth="200">', - ' <SegmentTemplate media="1.mp4" duration="1" />', - ' </Representation>', - ' </AdaptationSet>', - ' <AdaptationSet mimeType="video/mp4" lang="en" group="1">', - ' <Accessibility schemeIdUri="urn:scte:dash:cc:cea-608:2015"', - ' value="1=lang:eng;3=lang:swe,war:1,er:1"/>', - ' <Representation bandwidth="200">', - ' <SegmentTemplate media="1.mp4" duration="1" />', - ' </Representation>', - ' </AdaptationSet>', - ' </Period>', - '</MPD>', - ].join('\n'); + const source = [ + '<MPD minBufferTime="PT75S">', + ' <Period id="1" duration="PT30S">', + ' <AdaptationSet mimeType="video/mp4" lang="en" group="1">', + ' <Accessibility schemeIdUri="urn:scte:dash:cc:cea-608:2015"', + ' value="CC1=eng;CC3=swe"/>', + ' <Representation bandwidth="200">', + ' <SegmentTemplate media="1.mp4" duration="1" />', + ' </Representation>', + ' </AdaptationSet>', + ' <AdaptationSet mimeType="video/mp4" lang="en" group="1">', + ' <Accessibility schemeIdUri="urn:scte:dash:cc:cea-608:2015"', + ' value="CC1=lang:eng;CC3=lang:swe"/>', + ' <Representation bandwidth="200">', + ' <SegmentTemplate media="1.mp4" duration="1" />', + ' </Representation>', + ' </AdaptationSet>', + ' <AdaptationSet mimeType="video/mp4" lang="en" group="1">', + ' <Accessibility schemeIdUri="urn:scte:dash:cc:cea-608:2015"', + ' value="1=lang:eng;3=lang:swe,war:1,er:1"/>', + ' <Representation bandwidth="200">', + ' <SegmentTemplate media="1.mp4" duration="1" />', + ' </Representation>', + ' </AdaptationSet>', + ' </Period>', + '</MPD>', + ].join('\n'); - fakeNetEngine.setResponseText('dummy://foo', source); + fakeNetEngine.setResponseText('dummy://foo', source); - const manifest = await parser.start('dummy://foo', playerInterface); - // First Representation should be dropped. - const period = manifest.periods[0]; - const stream1 = period.variants[0].video; - const stream2 = period.variants[1].video; - const stream3 = period.variants[2].video; + const manifest = await parser.start('dummy://foo', playerInterface); + // First Representation should be dropped. + const period = manifest.periods[0]; + const stream1 = period.variants[0].video; + const stream2 = period.variants[1].video; + const stream3 = period.variants[2].video; - const expectedClosedCaptions = new Map( - [['CC1', shaka.util.LanguageUtils.normalize('eng')], - ['CC3', shaka.util.LanguageUtils.normalize('swe')]] - ); - expect(stream1.closedCaptions).toEqual(expectedClosedCaptions); - expect(stream2.closedCaptions).toEqual(expectedClosedCaptions); - expect(stream3.closedCaptions).toEqual(expectedClosedCaptions); - }); + const expectedClosedCaptions = new Map( + [['CC1', shaka.util.LanguageUtils.normalize('eng')], + ['CC3', shaka.util.LanguageUtils.normalize('swe')]] + ); + expect(stream1.closedCaptions).toEqual(expectedClosedCaptions); + expect(stream2.closedCaptions).toEqual(expectedClosedCaptions); + expect(stream3.closedCaptions).toEqual(expectedClosedCaptions); + }); it('correctly parses closed captions without channel numbers', async () => { const source = [ @@ -380,34 +380,34 @@ describe('DashParser Manifest', () => { const manifest = await parser.start('dummy://foo', playerInterface); const stream = manifest.periods[0].variants[0].video; const expectedClosedCaptions = new Map( - [['CC1', shaka.util.LanguageUtils.normalize('eng')], - ['CC3', shaka.util.LanguageUtils.normalize('swe')]] + [['CC1', shaka.util.LanguageUtils.normalize('eng')], + ['CC3', shaka.util.LanguageUtils.normalize('swe')]] ); expect(stream.closedCaptions).toEqual(expectedClosedCaptions); }); it('correctly parses closed captions with no channel and language info', async () => { - const source = [ - '<MPD minBufferTime="PT75S">', - ' <Period id="1" duration="PT30S">', - ' <AdaptationSet mimeType="video/mp4" lang="en" group="1">', - ' <Accessibility schemeIdUri="urn:scte:dash:cc:cea-608:2015"/>', - ' <Representation bandwidth="200">', - ' <SegmentTemplate media="1.mp4" duration="1" />', - ' </Representation>', - ' </AdaptationSet>', - ' </Period>', - '</MPD>', - ].join('\n'); + const source = [ + '<MPD minBufferTime="PT75S">', + ' <Period id="1" duration="PT30S">', + ' <AdaptationSet mimeType="video/mp4" lang="en" group="1">', + ' <Accessibility schemeIdUri="urn:scte:dash:cc:cea-608:2015"/>', + ' <Representation bandwidth="200">', + ' <SegmentTemplate media="1.mp4" duration="1" />', + ' </Representation>', + ' </AdaptationSet>', + ' </Period>', + '</MPD>', + ].join('\n'); - fakeNetEngine.setResponseText('dummy://foo', source); + fakeNetEngine.setResponseText('dummy://foo', source); - const manifest = await parser.start('dummy://foo', playerInterface); - const stream = manifest.periods[0].variants[0].video; - const expectedClosedCaptions = new Map([['CC1', 'und']]); - expect(stream.closedCaptions).toEqual(expectedClosedCaptions); - }); + const manifest = await parser.start('dummy://foo', playerInterface); + const stream = manifest.periods[0].variants[0].video; + const expectedClosedCaptions = new Map([['CC1', 'und']]); + expect(stream.closedCaptions).toEqual(expectedClosedCaptions); + }); it('correctly parses UTF-8', async () => { const source = [ diff --git a/test/dash/dash_parser_segment_list_unit.js b/test/dash/dash_parser_segment_list_unit.js index df33b361a..7a67250a4 100644 --- a/test/dash/dash_parser_segment_list_unit.js +++ b/test/dash/dash_parser_segment_list_unit.js @@ -56,7 +56,7 @@ describe('DashParser SegmentList', () => { '</SegmentList>', ], 30 /* duration */); const references = [ManifestParser.makeReference('s1.mp4', 1, - 0, 30, baseUri)]; + 0, 30, baseUri)]; await Dash.testSegmentIndex(source, references); }); diff --git a/test/dash/mpd_utils_unit.js b/test/dash/mpd_utils_unit.js index 9c21f2f62..a512b7fda 100644 --- a/test/dash/mpd_utils_unit.js +++ b/test/dash/mpd_utils_unit.js @@ -35,7 +35,7 @@ describe('MpdUtils', () => { MpdUtils.fillUriTemplate( '/example/$RepresentationID$.mp4', null, null, null, null).toString()) - .toBe('/example/$RepresentationID$.mp4'); + .toBe('/example/$RepresentationID$.mp4'); }); it('handles a single Number identifier', () => { @@ -53,7 +53,7 @@ describe('MpdUtils', () => { MpdUtils.fillUriTemplate( '/example/$Number$.mp4', null, null, null, null).toString()) - .toBe('/example/$Number$.mp4'); + .toBe('/example/$Number$.mp4'); }); it('handles a single Bandwidth identifier', () => { @@ -71,7 +71,7 @@ describe('MpdUtils', () => { MpdUtils.fillUriTemplate( '/example/$Bandwidth$.mp4', null, null, null, null).toString()) - .toBe('/example/$Bandwidth$.mp4'); + .toBe('/example/$Bandwidth$.mp4'); }); it('handles a single Time identifier', () => { @@ -89,7 +89,7 @@ describe('MpdUtils', () => { MpdUtils.fillUriTemplate( '/example/$Time$.mp4', null, null, null, null).toString()) - .toBe('/example/$Time$.mp4'); + .toBe('/example/$Time$.mp4'); }); it('handles rounding errors for calculated Times', () => { @@ -759,7 +759,7 @@ describe('MpdUtils', () => { const xml = parser.parseFromString(baseXMLString, 'text/xml') .documentElement; return MpdUtils.processXlinks(xml, retry, failGracefully, 'https://base', - fakeNetEngine).promise; + fakeNetEngine).promise; } }); }); diff --git a/test/hls/hls_live_unit.js b/test/hls/hls_live_unit.js index 8b36c456f..e5a675a7c 100644 --- a/test/hls/hls_live_unit.js +++ b/test/hls/hls_live_unit.js @@ -111,8 +111,8 @@ describe('HlsParser live', () => { rolloverOffset = (0x200000000 * 2) / 90000; selfInitializingSegmentData = shaka.util.Uint8ArrayUtils.concat( - new Uint8Array(initSegmentData), - new Uint8Array(segmentData)).buffer; + new Uint8Array(initSegmentData), + new Uint8Array(segmentData)).buffer; fakeNetEngine = new shaka.test.FakeNetworkingEngine(); @@ -152,7 +152,7 @@ describe('HlsParser live', () => { * @param {!Array} updatedReferences */ function testUpdate(done, master, initialMedia, initialReferences, - updatedMedia, updatedReferences) { + updatedMedia, updatedReferences) { fakeNetEngine .setResponseText('test:/master', master) .setResponseText('test:/video', initialMedia) @@ -164,7 +164,7 @@ describe('HlsParser live', () => { .setResponseValue('test:/selfInit.mp4', selfInitializingSegmentData); parser.start('test:/master', playerInterface) - .then((manifest) => { + .then((manifest) => { const variants = manifest.periods[0].variants; for (let i = 0; i < variants.length; i++) { const video = variants[i].video; @@ -225,12 +225,12 @@ describe('HlsParser live', () => { .setResponseValue('test:/main.mp4', segmentData); parser.start('test:/master', playerInterface) - .then((manifest) => { + .then((manifest) => { expect(manifest.presentationTimeline.isLive()).toBe(false); expect(manifest.presentationTimeline.isInProgress()).toBe(false); }) - .catch(fail) - .then(done); + .catch(fail) + .then(done); }); describe('update', () => { @@ -247,12 +247,12 @@ describe('HlsParser live', () => { it('adds new segments when they appear', (done) => { const ref1 = ManifestParser.makeReference('test:/main.mp4', - 0, 2, 4); + 0, 2, 4); const ref2 = ManifestParser.makeReference('test:/main2.mp4', - 1, 4, 6); + 1, 4, 6); testUpdate(done, master, media, [ref1], - mediaWithAdditionalSegment, [ref1, ref2]); + mediaWithAdditionalSegment, [ref1, ref2]); }); it('updates all variants', (done) => { @@ -264,12 +264,12 @@ describe('HlsParser live', () => { const masterWithTwoVariants = master + secondVariant; const ref1 = ManifestParser.makeReference('test:/main.mp4', - 0, 2, 4); + 0, 2, 4); const ref2 = ManifestParser.makeReference('test:/main2.mp4', - 1, 4, 6); + 1, 4, 6); testUpdate(done, masterWithTwoVariants, media, [ref1], - mediaWithAdditionalSegment, [ref1, ref2]); + mediaWithAdditionalSegment, [ref1, ref2]); }); it('updates all streams', (done) => { @@ -280,12 +280,12 @@ describe('HlsParser live', () => { const masterWithAudio = master + audio; const ref1 = ManifestParser.makeReference('test:/main.mp4', - 0, 2, 4); + 0, 2, 4); const ref2 = ManifestParser.makeReference('test:/main2.mp4', - 1, 4, 6); + 1, 4, 6); testUpdate(done, masterWithAudio, media, [ref1], - mediaWithAdditionalSegment, [ref1, ref2]); + mediaWithAdditionalSegment, [ref1, ref2]); }); it('handles multiple updates', (done) => { @@ -302,11 +302,11 @@ describe('HlsParser live', () => { const updatedMedia1 = media + newSegment1; const updatedMedia2 = updatedMedia1 + newSegment2; const ref1 = ManifestParser.makeReference('test:/main.mp4', - 0, 2, 4); + 0, 2, 4); const ref2 = ManifestParser.makeReference('test:/main2.mp4', - 1, 4, 6); + 1, 4, 6); const ref3 = ManifestParser.makeReference('test:/main3.mp4', - 2, 6, 8); + 2, 6, 8); fakeNetEngine .setResponseText('test:/master', master) @@ -315,7 +315,7 @@ describe('HlsParser live', () => { .setResponseValue('test:/main.mp4', segmentData); parser.start('test:/master', playerInterface) - .then((manifest) => { + .then((manifest) => { const video = manifest.periods[0].variants[0].video; ManifestParser.verifySegmentIndex(video, [ref1]); @@ -348,7 +348,7 @@ describe('HlsParser live', () => { fakeNetEngine .setResponseText('test:/master', master) .setResponseText('test:/video', - mediaWithAdditionalSegment + '#EXT-X-ENDLIST\n'); + mediaWithAdditionalSegment + '#EXT-X-ENDLIST\n'); delayForUpdatePeriod(); expect(manifest.presentationTimeline.isLive()).toBe(false); @@ -358,10 +358,10 @@ describe('HlsParser live', () => { it('starts presentation as VOD when ENDLIST is present', (done) => { fakeNetEngine - .setResponseText('test:/master', master) - .setResponseText('test:/video', media + '#EXT-X-ENDLIST') - .setResponseValue('test:/init.mp4', initSegmentData) - .setResponseValue('test:/main.mp4', segmentData); + .setResponseText('test:/master', master) + .setResponseText('test:/video', media + '#EXT-X-ENDLIST') + .setResponseValue('test:/init.mp4', initSegmentData) + .setResponseValue('test:/main.mp4', segmentData); parser.start('test:/master', playerInterface).then((manifest) => { expect(manifest.presentationTimeline.isLive()).toBe(false); @@ -447,10 +447,10 @@ describe('HlsParser live', () => { it('does not fail on a missing sequence number', (done) => { fakeNetEngine - .setResponseText('test:/master', master) - .setResponseText('test:/video', mediaWithoutSequenceNumber) - .setResponseValue('test:/init.mp4', initSegmentData) - .setResponseValue('test:/main.mp4', segmentData); + .setResponseText('test:/master', master) + .setResponseText('test:/video', mediaWithoutSequenceNumber) + .setResponseValue('test:/init.mp4', initSegmentData) + .setResponseValue('test:/main.mp4', segmentData); parser.start('test:/master', playerInterface).catch(fail).then(done); }); @@ -544,27 +544,27 @@ describe('HlsParser live', () => { it('adds new segments when they appear', (done) => { const ref1 = ManifestParser.makeReference('test:/main.mp4', - 0, 2, 4); + 0, 2, 4); const ref2 = ManifestParser.makeReference('test:/main2.mp4', - 1, 4, 6); + 1, 4, 6); testUpdate(done, master, media, [ref1], - mediaWithAdditionalSegment, [ref1, ref2]); + mediaWithAdditionalSegment, [ref1, ref2]); }); it('evicts removed segments', (done) => { const ref1 = ManifestParser.makeReference('test:/main.mp4', - 0, 2, 4); + 0, 2, 4); const ref2 = ManifestParser.makeReference('test:/main2.mp4', - 1, 4, 6); + 1, 4, 6); testUpdate(done, master, mediaWithAdditionalSegment, [ref1, ref2], - mediaWithRemovedSegment, [ref2]); + mediaWithRemovedSegment, [ref2]); }); it('handles updates with redirects', (done) => { const oldRef1 = ManifestParser.makeReference('test:/main.mp4', - 0, 2, 4); + 0, 2, 4); const newRef1 = ManifestParser.makeReference('test:/redirected/main.mp4', 0, 2, 4); @@ -585,7 +585,7 @@ describe('HlsParser live', () => { }); testUpdate(done, master, media, [oldRef1], - mediaWithAdditionalSegment, [newRef1, newRef2]); + mediaWithAdditionalSegment, [newRef1, newRef2]); }); it('parses start time from mp4 segments', (done) => { @@ -717,7 +717,7 @@ describe('HlsParser live', () => { 'video\n', ].join(''); - const textPlaylist1 = [ + const textPlaylist1 = [ '#EXTM3U\n', '#EXT-X-TARGETDURATION:5\n', '#EXT-X-MEDIA-SEQUENCE:0\n', @@ -764,13 +764,13 @@ describe('HlsParser live', () => { const baseTime = 95443 + rolloverOffset; const ref1 = ManifestParser.makeReference('test:/main1.vtt', - /* position */ 0, - /* startTime */ baseTime, - /* endTime */ baseTime + 2); + /* position */ 0, + /* startTime */ baseTime, + /* endTime */ baseTime + 2); const ref2 = ManifestParser.makeReference('test:/main2.vtt', - /* position */ 1, - /* startTime */ baseTime + 2, - /* endTime */ baseTime + 4); + /* position */ 1, + /* startTime */ baseTime + 2, + /* endTime */ baseTime + 4); parser.start('test:/master', playerInterface).then((manifest) => { const text = manifest.periods[0].textStreams[0]; diff --git a/test/hls/hls_parser_unit.js b/test/hls/hls_parser_unit.js index 419fb22a8..08e639d1b 100644 --- a/test/hls/hls_parser_unit.js +++ b/test/hls/hls_parser_unit.js @@ -78,8 +78,8 @@ describe('HlsParser', () => { // segment starts at 0s. selfInitializingSegmentData = shaka.util.Uint8ArrayUtils.concat( - new Uint8Array(initSegmentData), - new Uint8Array(segmentData)).buffer; + new Uint8Array(initSegmentData), + new Uint8Array(segmentData)).buffer; fakeNetEngine = new shaka.test.FakeNetworkingEngine(); @@ -1219,9 +1219,9 @@ describe('HlsParser', () => { const videoPosition = video.findSegmentPosition(0); const audioPosition = audio.findSegmentPosition(0); goog.asserts.assert(videoPosition != null, - 'Cannot find first video segment'); + 'Cannot find first video segment'); goog.asserts.assert(audioPosition != null, - 'Cannot find first audio segment'); + 'Cannot find first audio segment'); const videoReference = video.getSegmentReference(videoPosition); const audioReference = audio.getSegmentReference(audioPosition); @@ -1397,11 +1397,11 @@ describe('HlsParser', () => { .setResponseValue('test:/main.mp4', segmentData); parser.start('test:/master', playerInterface) - .then(fail) - .catch((e) => { - shaka.test.Util.expectToEqualError(e, error); - }) - .then(done); + .then(fail) + .catch((e) => { + shaka.test.Util.expectToEqualError(e, error); + }) + .then(done); } it('if multiple init sections were provided', (done) => { @@ -1933,12 +1933,12 @@ describe('HlsParser', () => { ].join(''); fakeNetEngine - .setResponseText('test:/master', master) - .setResponseText('test:/video0', media) - .setResponseText('test:/video1', media) - .setResponseText('test:/audio', media) - .setResponseValue('test:/init.mp4', initSegmentData) - .setResponseValue('test:/main.mp4', segmentData); + .setResponseText('test:/master', master) + .setResponseText('test:/video0', media) + .setResponseText('test:/video1', media) + .setResponseText('test:/audio', media) + .setResponseValue('test:/init.mp4', initSegmentData) + .setResponseValue('test:/main.mp4', segmentData); const manifest = await parser.start('test:/master', playerInterface); expect(manifest.periods[0].variants.length).toBe(2); @@ -1970,11 +1970,11 @@ describe('HlsParser', () => { ].join(''); fakeNetEngine - .setResponseText('media/master', master) // Relative master URI - .setResponseText('http://foo/media/audio', media) - .setResponseText('http://foo/media/video', media) - .setResponseValue('http://foo/media/init.mp4', initSegmentData) - .setResponseValue('http://foo/media/main.mp4', segmentData); + .setResponseText('media/master', master) // Relative master URI + .setResponseText('http://foo/media/audio', media) + .setResponseText('http://foo/media/video', media) + .setResponseValue('http://foo/media/init.mp4', initSegmentData) + .setResponseValue('http://foo/media/main.mp4', segmentData); fakeNetEngine.setResponseFilter((type, response) => { // Simulate support for relative URIs in the browser by setting the diff --git a/test/hls/manifest_text_parser_unit.js b/test/hls/manifest_text_parser_unit.js index d68b5b52d..1f2b708ba 100644 --- a/test/hls/manifest_text_parser_unit.js +++ b/test/hls/manifest_text_parser_unit.js @@ -27,14 +27,14 @@ describe('ManifestTextParser', () => { describe('parsePlaylist', () => { it('rejects invalid playlists', () => { verifyError('invalid playlist', - shaka.util.Error.Code.HLS_PLAYLIST_HEADER_MISSING); + shaka.util.Error.Code.HLS_PLAYLIST_HEADER_MISSING); // This Master playlist is invalid cause it contains a segment tag. // All segment information should be in a Media playlist. verifyError('#EXTM3U\n' + '#EXT-X-MEDIA:TYPE=AUDIO\n' + '#EXTINF:6.00600', - shaka.util.Error.Code.HLS_INVALID_PLAYLIST_HIERARCHY); + shaka.util.Error.Code.HLS_INVALID_PLAYLIST_HIERARCHY); }); it('parses a Media Playlist', () => { @@ -226,7 +226,7 @@ describe('ManifestTextParser', () => { new shaka.hls.Tag(/* id */ 1, 'EXT-X-MEDIA', [ new shaka.hls.Attribute('CODECS', - 'avc1.64002a,mp4a.40.2,avc2.64000'), + 'avc1.64002a,mp4a.40.2,avc2.64000'), ]), ], }, @@ -245,7 +245,7 @@ describe('ManifestTextParser', () => { new shaka.hls.Tag(/* id */ 2, 'EXT-X-MEDIA', [ new shaka.hls.Attribute('CODECS', - 'avc1.64002a,mp4a.40.2'), + 'avc1.64002a,mp4a.40.2'), new shaka.hls.Attribute('AUDIO', 'a1,a2'), ]), ], @@ -338,10 +338,10 @@ describe('ManifestTextParser', () => { new shaka.hls.Segment('https://test/test.mp4', [ new shaka.hls.Tag( - /* id */ 2, - 'EXTINF', - [new shaka.hls.Attribute('pid', '180')], - '5.99467' + /* id */ 2, + 'EXTINF', + [new shaka.hls.Attribute('pid', '180')], + '5.99467' ), ]), ], @@ -366,15 +366,15 @@ describe('ManifestTextParser', () => { ], segments: [ new shaka.hls.Segment('https://test/test.mp4', - [ - new shaka.hls.Tag(/* id */ 1, 'EXT-X-KEY', - [ - new shaka.hls.Attribute('METHOD', 'AES-128'), - new shaka.hls.Attribute('URI', 'http://key.com'), - new shaka.hls.Attribute('IV', '123'), - ]), - new shaka.hls.Tag(/* id */ 3, 'EXTINF', [], '5.99467'), - ]), + [ + new shaka.hls.Tag(/* id */ 1, 'EXT-X-KEY', + [ + new shaka.hls.Attribute('METHOD', 'AES-128'), + new shaka.hls.Attribute('URI', 'http://key.com'), + new shaka.hls.Attribute('IV', '123'), + ]), + new shaka.hls.Tag(/* id */ 3, 'EXTINF', [], '5.99467'), + ]), ], }, @@ -433,9 +433,9 @@ describe('ManifestTextParser', () => { ], segments: [ new shaka.hls.Segment('https://test/uri', - [new shaka.hls.Tag(2, 'EXTINF', [], '5')]), + [new shaka.hls.Tag(2, 'EXTINF', [], '5')]), new shaka.hls.Segment('https://test/uri2', - [new shaka.hls.Tag(3, 'EXTINF', [], '4')]), + [new shaka.hls.Tag(3, 'EXTINF', [], '4')]), ], }, @@ -455,9 +455,9 @@ describe('ManifestTextParser', () => { ], segments: [ new shaka.hls.Segment('https://test/uri', - [new shaka.hls.Tag(2, 'EXTINF', [], '5')]), + [new shaka.hls.Tag(2, 'EXTINF', [], '5')]), new shaka.hls.Segment('https://test/uri2', - [new shaka.hls.Tag(3, 'EXTINF', [], '4')]), + [new shaka.hls.Tag(3, 'EXTINF', [], '4')]), ], }, diff --git a/test/media/drm_engine_integration.js b/test/media/drm_engine_integration.js index 2c138e007..bd8f9e701 100644 --- a/test/media/drm_engine_integration.js +++ b/test/media/drm_engine_integration.js @@ -265,13 +265,13 @@ describe('DrmEngine', () => { * @return {function(function())} */ function checkAndRun(test) { - return function(done) { - if (!support['com.widevine.alpha'] && + return function(done) { + if (!support['com.widevine.alpha'] && !support['com.microsoft.playready']) { - pending('Skipping DrmEngine tests.'); - } else { - test(done); - } - }; + pending('Skipping DrmEngine tests.'); + } else { + test(done); + } + }; } }); diff --git a/test/media/drm_engine_unit.js b/test/media/drm_engine_unit.js index 7acec1d4f..4543eddab 100644 --- a/test/media/drm_engine_unit.js +++ b/test/media/drm_engine_unit.js @@ -972,13 +972,13 @@ describe('DrmEngine', () => { }); it('uses license server for "individualization-request" by default', - async () => { - config.advanced['drm.abc'] = createAdvancedConfig(null); - config.advanced['drm.abc'].individualizationServer = ''; + async () => { + config.advanced['drm.abc'] = createAdvancedConfig(null); + config.advanced['drm.abc'].individualizationServer = ''; - await sendMessageTest( - 'http://abc.drm/license', 'individualization-request'); - }); + await sendMessageTest( + 'http://abc.drm/license', 'individualization-request'); + }); it('dispatches an error if license request fails', async () => { onErrorSpy.and.stub(); @@ -1816,7 +1816,7 @@ describe('DrmEngine', () => { serverCertificate: serverCert, initData: ['blah', 'init data'], keyIds: ['deadbeefdeadbeefdeadbeefdeadbeef', - 'eadbeefdeadbeefdeadbeefdeadbeefd'], + 'eadbeefdeadbeefdeadbeefdeadbeefd'], }; const returned = shaka.media.DrmEngine.getCommonDrmInfos([drmInfoVideo], [drmInfoAudio]); diff --git a/test/media/media_source_engine_integration.js b/test/media/media_source_engine_integration.js index 6d3da0622..863471c90 100644 --- a/test/media/media_source_engine_integration.js +++ b/test/media/media_source_engine_integration.js @@ -300,9 +300,9 @@ describe('MediaSourceEngine', () => { await mediaSourceEngine.setDuration(presentationDuration); await appendInit(ContentType.VIDEO); await mediaSourceEngine.setStreamProperties(ContentType.VIDEO, - /* timestampOffset */ 0, - /* appendWindowStart */ 5, - /* appendWindowEnd */ 18); + /* timestampOffset */ 0, + /* appendWindowStart */ 5, + /* appendWindowEnd */ 18); expect(buffered(ContentType.VIDEO, 0)).toBe(0); await append(ContentType.VIDEO, 1); expect(bufferStart(ContentType.VIDEO)).toBeCloseTo(5, 1); @@ -319,9 +319,9 @@ describe('MediaSourceEngine', () => { await appendInit(ContentType.VIDEO); // Simulate period 1, with 20 seconds of content, no timestamp offset await mediaSourceEngine.setStreamProperties(ContentType.VIDEO, - /* timestampOffset */ 0, - /* appendWindowStart */ 0, - /* appendWindowEnd */ 20); + /* timestampOffset */ 0, + /* appendWindowStart */ 0, + /* appendWindowEnd */ 20); await append(ContentType.VIDEO, 1); await append(ContentType.VIDEO, 2); expect(bufferStart(ContentType.VIDEO)).toBeCloseTo(0, 1); @@ -331,9 +331,9 @@ describe('MediaSourceEngine', () => { // The 5 seconds of overlap should be trimmed off, and we should still // have a continuous stream with 35 seconds of content. await mediaSourceEngine.setStreamProperties(ContentType.VIDEO, - /* timestampOffset */ 15, - /* appendWindowStart */ 20, - /* appendWindowEnd */ 35); + /* timestampOffset */ 15, + /* appendWindowStart */ 20, + /* appendWindowEnd */ 35); await append(ContentType.VIDEO, 1); await append(ContentType.VIDEO, 2); expect(bufferStart(ContentType.VIDEO)).toBeCloseTo(0, 1); diff --git a/test/media/media_source_engine_unit.js b/test/media/media_source_engine_unit.js index 2af69d706..d608ac7e6 100644 --- a/test/media/media_source_engine_unit.js +++ b/test/media/media_source_engine_unit.js @@ -354,7 +354,7 @@ describe('MediaSourceEngine', () => { mockVideo.error = {code: 5}; try { await mediaSourceEngine.appendBuffer(ContentType.AUDIO, buffer, null, - null, /* hasClosedCaptions */ false); + null, /* hasClosedCaptions */ false); fail('not reached'); } catch (error) { expect(error.code).toBe( @@ -373,7 +373,7 @@ describe('MediaSourceEngine', () => { mockVideo.error = {code: 5}; try { await mediaSourceEngine.appendBuffer(ContentType.AUDIO, buffer, null, - null, /* hasClosedCaptions */ false); + null, /* hasClosedCaptions */ false); fail('not reached'); } catch (error) { expect(error.code).toBe(shaka.util.Error.Code.QUOTA_EXCEEDED_ERROR); @@ -386,15 +386,15 @@ describe('MediaSourceEngine', () => { mockVideo.error = {code: 5}; mediaSourceEngine.appendBuffer(ContentType.AUDIO, buffer, null, null, /* hasClosedCaptions */ false).then(() => { - fail('not reached'); - done(); - }, (error) => { - expect(error.code).toBe( - shaka.util.Error.Code.MEDIA_SOURCE_OPERATION_FAILED); - expect(error.data).toEqual([5]); - expect(audioSourceBuffer.appendBuffer).toHaveBeenCalledWith(buffer); - done(); - }); + fail('not reached'); + done(); + }, (error) => { + expect(error.code).toBe( + shaka.util.Error.Code.MEDIA_SOURCE_OPERATION_FAILED); + expect(error.data).toEqual([5]); + expect(audioSourceBuffer.appendBuffer).toHaveBeenCalledWith(buffer); + done(); + }); audioSourceBuffer.error(); audioSourceBuffer.updateend(); }); @@ -576,31 +576,31 @@ describe('MediaSourceEngine', () => { it('appends closed caption data only when mux.js is available', async () => { - const originalMuxjs = window.muxjs; + const originalMuxjs = window.muxjs; - try { - window['muxjs'] = null; - const initObject = new Map(); - initObject.set(ContentType.VIDEO, fakeVideoStream); - await mediaSourceEngine.init(initObject, false); + try { + window['muxjs'] = null; + const initObject = new Map(); + initObject.set(ContentType.VIDEO, fakeVideoStream); + await mediaSourceEngine.init(initObject, false); - const appendBuffer = mediaSourceEngine.appendBuffer( - ContentType.VIDEO, buffer, null, null, true); - // In MediaSourceEngine, appendBuffer() is async and Promise-based, but - // at the browser level, it's event-based. - // MediaSourceEngine waits for the 'updateend' event from the - // SourceBuffer, and uses that to resolve the appendBuffer Promise. - // Here, we must trigger the event on the fake/mock SourceBuffer before - // waiting on the appendBuffer Promise. - videoSourceBuffer.updateend(); - await appendBuffer; - expect(mockClosedCaptionParser.initSpy).not.toHaveBeenCalled(); - expect(mockTextEngine.storeAndAppendClosedCaptions).not - .toHaveBeenCalled(); - } finally { - window['muxjs'] = originalMuxjs; - } - }); + const appendBuffer = mediaSourceEngine.appendBuffer( + ContentType.VIDEO, buffer, null, null, true); + // In MediaSourceEngine, appendBuffer() is async and Promise-based, but + // at the browser level, it's event-based. + // MediaSourceEngine waits for the 'updateend' event from the + // SourceBuffer, and uses that to resolve the appendBuffer Promise. + // Here, we must trigger the event on the fake/mock SourceBuffer before + // waiting on the appendBuffer Promise. + videoSourceBuffer.updateend(); + await appendBuffer; + expect(mockClosedCaptionParser.initSpy).not.toHaveBeenCalled(); + expect(mockTextEngine.storeAndAppendClosedCaptions).not + .toHaveBeenCalled(); + } finally { + window['muxjs'] = originalMuxjs; + } + }); }); describe('remove', () => { @@ -801,9 +801,9 @@ describe('MediaSourceEngine', () => { expect(mockTextEngine.setTimestampOffset).not.toHaveBeenCalled(); expect(mockTextEngine.setAppendWindow).not.toHaveBeenCalled(); await mediaSourceEngine.setStreamProperties(ContentType.TEXT, - /* timestampOffset */ 10, - /* appendWindowStart */ 0, - /* appendWindowEnd */ 20); + /* timestampOffset */ 10, + /* appendWindowStart */ 0, + /* appendWindowEnd */ 20); expect(mockTextEngine.setTimestampOffset).toHaveBeenCalledWith(10); expect(mockTextEngine.setAppendWindow).toHaveBeenCalledWith(0, 20); }); @@ -1012,9 +1012,9 @@ describe('MediaSourceEngine', () => { it('waits for all operations to complete', async () => { mediaSourceEngine.appendBuffer(ContentType.AUDIO, buffer, null, null, - /* hasClosedCaptions */ false); + /* hasClosedCaptions */ false); mediaSourceEngine.appendBuffer(ContentType.VIDEO, buffer, null, null, - /* hasClosedCaptions */ false); + /* hasClosedCaptions */ false); /** @type {!shaka.test.StatusPromise} */ const p = new shaka.test.StatusPromise(mediaSourceEngine.destroy()); @@ -1061,7 +1061,7 @@ describe('MediaSourceEngine', () => { it('cancels operations that have not yet started', async () => { mediaSourceEngine.appendBuffer( - ContentType.AUDIO, buffer, null, null, /* hasClosedCaptions */ false); + ContentType.AUDIO, buffer, null, null, /* hasClosedCaptions */ false); /** @type {!shaka.test.StatusPromise} */ const rejected = new shaka.test.StatusPromise(mediaSourceEngine.appendBuffer( diff --git a/test/media/mp4_segment_index_parser_unit.js b/test/media/mp4_segment_index_parser_unit.js index 809f67975..239d8a72b 100644 --- a/test/media/mp4_segment_index_parser_unit.js +++ b/test/media/mp4_segment_index_parser_unit.js @@ -50,11 +50,11 @@ describe('Mp4SegmentIndexParser', () => { const result = shaka.media.Mp4SegmentIndexParser(indexSegment, 0, [], 0); const references = [ - {startTime: 0, endTime: 12, startByte: 92, endByte: 194960}, - {startTime: 12, endTime: 24, startByte: 194961, endByte: 294059}, - {startTime: 24, endTime: 36, startByte: 294060, endByte: 466352}, - {startTime: 36, endTime: 48, startByte: 466353, endByte: 615511}, - {startTime: 48, endTime: 60, startByte: 615512, endByte: 743301}, + {startTime: 0, endTime: 12, startByte: 92, endByte: 194960}, + {startTime: 12, endTime: 24, startByte: 194961, endByte: 294059}, + {startTime: 24, endTime: 36, startByte: 294060, endByte: 466352}, + {startTime: 36, endTime: 48, startByte: 466353, endByte: 615511}, + {startTime: 48, endTime: 60, startByte: 615512, endByte: 743301}, ]; expect(result).toBeTruthy(); @@ -73,11 +73,11 @@ describe('Mp4SegmentIndexParser', () => { const result = shaka.media.Mp4SegmentIndexParser(indexSegment, 0, [], 2); const references = [ - {startTime: -2, endTime: 10}, - {startTime: 10, endTime: 22}, - {startTime: 22, endTime: 34}, - {startTime: 34, endTime: 46}, - {startTime: 46, endTime: 58}, + {startTime: -2, endTime: 10}, + {startTime: 10, endTime: 22}, + {startTime: 22, endTime: 34}, + {startTime: 34, endTime: 46}, + {startTime: 46, endTime: 58}, ]; expect(result).toBeTruthy(); diff --git a/test/media/presentation_timeline_unit.js b/test/media/presentation_timeline_unit.js index e50febcb6..66a60760b 100644 --- a/test/media/presentation_timeline_unit.js +++ b/test/media/presentation_timeline_unit.js @@ -128,15 +128,15 @@ describe('PresentationTimeline', () => { * @return {shaka.media.SegmentReference} */ function makeSegmentReference(startTime, endTime) { - // start and end times are the only fields that matter to - // PresentationTimeline. - return new shaka.media.SegmentReference( - /* position */ 0, - startTime, - endTime, - /* uris */ (() => { return []; }), - /* startByte */ 0, - /* endByte */ null); + // start and end times are the only fields that matter to + // PresentationTimeline. + return new shaka.media.SegmentReference( + /* position */ 0, + startTime, + endTime, + /* uris */ (() => { return []; }), + /* startByte */ 0, + /* endByte */ null); } describe('getSegmentAvailabilityStart', () => { @@ -208,7 +208,7 @@ describe('PresentationTimeline', () => { // See https://github.com/google/shaka-player/issues/999 setElapsed(1000); timeline.notifySegments([ref1, ref2, ref3, ref4, ref5], - /* periodStart */ 0); + /* periodStart */ 0); // last segment time (50) - availability (20) expect(timeline.getSegmentAvailabilityStart()).toBe(30); @@ -226,7 +226,7 @@ describe('PresentationTimeline', () => { setElapsed(100); timeline.notifySegments([ref1, ref2, ref3, ref4, ref5], - /* periodStart */ 0); + /* periodStart */ 0); // now (100) - max segment duration (10) - availability start time (0) expect(timeline.getSegmentAvailabilityEnd()).toBe(90); @@ -309,7 +309,7 @@ describe('PresentationTimeline', () => { // See https://github.com/google/shaka-player/issues/999 setElapsed(1000); timeline.notifySegments([ref1, ref2, ref3, ref4, ref5], - /* periodStart */ 0); + /* periodStart */ 0); // last segment time (50) expect(timeline.getSegmentAvailabilityEnd()).toBe(50); @@ -407,11 +407,11 @@ describe('PresentationTimeline', () => { // A reference from 30-40, + period start 0 timeline.notifySegments([makeSegmentReference(30, 40)], - /* periodStart */ 0); + /* periodStart */ 0); // A reference from 0-10, + period start 40 timeline.notifySegments([makeSegmentReference(0, 10)], - /* periodStart */ 40); + /* periodStart */ 40); // If we hadn't adjusted for period start, this would be 0. expect(timeline.getSeekRangeStart()).toBe(30); diff --git a/test/media/region_observer_unit.js b/test/media/region_observer_unit.js index e31ba15f3..999eb074a 100644 --- a/test/media/region_observer_unit.js +++ b/test/media/region_observer_unit.js @@ -85,8 +85,8 @@ describe('RegionObserver', () => { expect(onEnterRegion).toHaveBeenCalledOnceMoreWith([region, false]); poll(observer, - /* timeInSeconds= */ 8, - /* seeking= */ false); + /* timeInSeconds= */ 8, + /* seeking= */ false); expect(onEnterRegion).not.toHaveBeenCalled(); expect(onExitRegion).not.toHaveBeenCalled(); expect(onSkipRegion).not.toHaveBeenCalled(); diff --git a/test/media/streaming_engine_integration.js b/test/media/streaming_engine_integration.js index fe545dc47..404cd6282 100644 --- a/test/media/streaming_engine_integration.js +++ b/test/media/streaming_engine_integration.js @@ -198,7 +198,7 @@ describe('StreamingEngine', () => { } function setupNetworkingEngine(firstPeriodStartTime, secondPeriodStartTime, - presentationDuration, segmentDurations) { + presentationDuration, segmentDurations) { const periodStartTimes = [firstPeriodStartTime, secondPeriodStartTime]; const boundsCheckPosition = @@ -263,7 +263,7 @@ describe('StreamingEngine', () => { video: metadata.video.segmentDuration}); manifest.presentationTimeline = - /** @type {!shaka.media.PresentationTimeline} */ (timeline); + /** @type {!shaka.media.PresentationTimeline} */ (timeline); manifest.minBufferTime = 2; // Create InitSegmentReferences. @@ -549,7 +549,7 @@ describe('StreamingEngine', () => { expect(video.currentTime).toBeLessThan(20); done(); }) - .catch(done.fail); + .catch(done.fail); }); // Let's go! diff --git a/test/media/streaming_engine_unit.js b/test/media/streaming_engine_unit.js index ea5fade40..7b9ac788f 100644 --- a/test/media/streaming_engine_unit.js +++ b/test/media/streaming_engine_unit.js @@ -231,7 +231,7 @@ describe('StreamingEngine', () => { audio: { initSegments: [makeBuffer(initSegmentSizeAudio), - makeBuffer(initSegmentSizeAudio)], + makeBuffer(initSegmentSizeAudio)], segments: [], segmentStartTimes: [], segmentPeriodTimes: [], @@ -240,7 +240,7 @@ describe('StreamingEngine', () => { video: { initSegments: [makeBuffer(initSegmentSizeVideo), - makeBuffer(initSegmentSizeVideo)], + makeBuffer(initSegmentSizeVideo)], segments: [], segmentStartTimes: [], segmentPeriodTimes: [], @@ -351,7 +351,7 @@ describe('StreamingEngine', () => { segmentDurations); manifest.presentationTimeline = - /** @type {!shaka.media.PresentationTimeline} */ (timeline); + /** @type {!shaka.media.PresentationTimeline} */ (timeline); manifest.minBufferTime = 2; // Create InitSegmentReferences. @@ -1359,11 +1359,11 @@ describe('StreamingEngine', () => { onTick.and.callFake(() => { // Verify that all buffers have been cleared. expect(mediaSourceEngine.clear) - .toHaveBeenCalledWith(ContentType.AUDIO); + .toHaveBeenCalledWith(ContentType.AUDIO); expect(mediaSourceEngine.clear) - .toHaveBeenCalledWith(ContentType.VIDEO); + .toHaveBeenCalledWith(ContentType.VIDEO); expect(mediaSourceEngine.clear) - .toHaveBeenCalledWith(ContentType.TEXT); + .toHaveBeenCalledWith(ContentType.TEXT); onTick.and.stub(); }); @@ -1445,11 +1445,11 @@ describe('StreamingEngine', () => { onTick.and.callFake(() => { // Verify that all buffers have been cleared. expect(mediaSourceEngine.clear) - .toHaveBeenCalledWith(ContentType.AUDIO); + .toHaveBeenCalledWith(ContentType.AUDIO); expect(mediaSourceEngine.clear) - .toHaveBeenCalledWith(ContentType.VIDEO); + .toHaveBeenCalledWith(ContentType.VIDEO); expect(mediaSourceEngine.clear) - .toHaveBeenCalledWith(ContentType.TEXT); + .toHaveBeenCalledWith(ContentType.TEXT); onTick.and.stub(); }); @@ -1983,7 +1983,7 @@ describe('StreamingEngine', () => { // Wrap the NetworkingEngine to cause errors. const targetUri = '1_audio_init'; failFirstRequestForTarget(netEngine, targetUri, - shaka.util.Error.Code.BAD_HTTP_STATUS); + shaka.util.Error.Code.BAD_HTTP_STATUS); mediaSourceEngine = new shaka.test.FakeMediaSourceEngine(segmentData); @@ -2018,7 +2018,7 @@ describe('StreamingEngine', () => { // Wrap the NetworkingEngine to cause errors. const targetUri = '1_audio_init'; failFirstRequestForTarget(netEngine, targetUri, - shaka.util.Error.Code.BAD_HTTP_STATUS); + shaka.util.Error.Code.BAD_HTTP_STATUS); mediaSourceEngine = new shaka.test.FakeMediaSourceEngine(segmentData); @@ -2053,7 +2053,7 @@ describe('StreamingEngine', () => { // Wrap the NetworkingEngine to cause errors. const targetUri = '1_audio_init'; failFirstRequestForTarget(netEngine, targetUri, - shaka.util.Error.Code.BAD_HTTP_STATUS); + shaka.util.Error.Code.BAD_HTTP_STATUS); mediaSourceEngine = new shaka.test.FakeMediaSourceEngine(segmentData); @@ -2087,7 +2087,7 @@ describe('StreamingEngine', () => { // Wrap the NetworkingEngine to cause errors. const targetUri = '1_audio_init'; failFirstRequestForTarget(netEngine, targetUri, - shaka.util.Error.Code.BAD_HTTP_STATUS); + shaka.util.Error.Code.BAD_HTTP_STATUS); mediaSourceEngine = new shaka.test.FakeMediaSourceEngine(segmentData); @@ -2130,7 +2130,7 @@ describe('StreamingEngine', () => { const targetUri = '1_audio_init'; const originalNetEngineRequest = netEngine.request; failFirstRequestForTarget(netEngine, targetUri, - shaka.util.Error.Code.BAD_HTTP_STATUS); + shaka.util.Error.Code.BAD_HTTP_STATUS); mediaSourceEngine = new shaka.test.FakeMediaSourceEngine(segmentData); createStreamingEngine(); @@ -2945,14 +2945,14 @@ describe('StreamingEngine', () => { }); it('doesn\'t abort if close to finished', - /** @suppress {accessControls} */ () => { - prepareForAbort(); - lastResponse.bytesRemaining_.setBytes(3); - streamingEngine.switchVariant( - newVariant, /* clear_buffer= */ false, /* safe_margin= */ 0); + /** @suppress {accessControls} */ () => { + prepareForAbort(); + lastResponse.bytesRemaining_.setBytes(3); + streamingEngine.switchVariant( + newVariant, /* clear_buffer= */ false, /* safe_margin= */ 0); - bufferAndCheck(/* didAbort= */ false); - }); + bufferAndCheck(/* didAbort= */ false); + }); it('accounts for init segment size', () => { newVariant.video.initSegmentReference = diff --git a/test/media/webm_segment_index_parser_unit.js b/test/media/webm_segment_index_parser_unit.js index 187439659..dd4fd64ef 100644 --- a/test/media/webm_segment_index_parser_unit.js +++ b/test/media/webm_segment_index_parser_unit.js @@ -62,11 +62,11 @@ describe('WebmSegmentIndexParser', () => { const result = parser.parse(indexSegment, initSegment, [], 0); const references = [ - {startTime: 0, endTime: 12, startByte: 281, endByte: 95911}, - {startTime: 12, endTime: 24, startByte: 95912, endByte: 209663}, - {startTime: 24, endTime: 36, startByte: 209664, endByte: 346545}, - {startTime: 36, endTime: 48, startByte: 346546, endByte: 458817}, - {startTime: 48, endTime: 60, startByte: 458818, endByte: null}, + {startTime: 0, endTime: 12, startByte: 281, endByte: 95911}, + {startTime: 12, endTime: 24, startByte: 95912, endByte: 209663}, + {startTime: 24, endTime: 36, startByte: 209664, endByte: 346545}, + {startTime: 36, endTime: 48, startByte: 346546, endByte: 458817}, + {startTime: 48, endTime: 60, startByte: 458818, endByte: null}, ]; expect(result).toBeTruthy(); @@ -84,11 +84,11 @@ describe('WebmSegmentIndexParser', () => { const result = parser.parse(indexSegment, initSegment, [], 2); const references = [ - {startTime: -2, endTime: 10}, - {startTime: 10, endTime: 22}, - {startTime: 22, endTime: 34}, - {startTime: 34, endTime: 46}, - {startTime: 46, endTime: 58}, + {startTime: -2, endTime: 10}, + {startTime: 10, endTime: 22}, + {startTime: 22, endTime: 34}, + {startTime: 34, endTime: 46}, + {startTime: 46, endTime: 58}, ]; expect(result).toBeTruthy(); diff --git a/test/net/http_plugin_unit.js b/test/net/http_plugin_unit.js index dfe88d457..b5f6f69f0 100644 --- a/test/net/http_plugin_unit.js +++ b/test/net/http_plugin_unit.js @@ -222,7 +222,7 @@ function httpPluginTests(usingFetch) { it('gets redirect URLs with 302 status', (done) => { testSucceeds('https://foo.bar/302', done, - 'https://foo.bar/after/302'); + 'https://foo.bar/after/302'); PromiseMock.flush(); }); diff --git a/test/net/networking_engine_unit.js b/test/net/networking_engine_unit.js index 1847bc45d..a7c78b286 100644 --- a/test/net/networking_engine_unit.js +++ b/test/net/networking_engine_unit.js @@ -58,7 +58,7 @@ describe('NetworkingEngine', /** @suppress {accessControls} */ () => { networkingEngine = new shaka.net.NetworkingEngine(Util.spyFunc(onProgress)); resolveScheme = makeResolveScheme('resolve scheme'); rejectScheme = jasmine.createSpy('reject scheme').and.callFake(() => - shaka.util.AbortableOperation.failed(error)); + shaka.util.AbortableOperation.failed(error)); shaka.net.NetworkingEngine.registerScheme( 'resolve', Util.spyFunc(resolveScheme), shaka.net.NetworkingEngine.PluginPriority.FALLBACK); @@ -177,7 +177,7 @@ describe('NetworkingEngine', /** @suppress {accessControls} */ () => { } catch (e) { expect(deferSpy.calls.count()).toBe(1); expect(deferSpy).toHaveBeenCalledWith(baseDelay, - jasmine.any(Function)); + jasmine.any(Function)); } }); @@ -196,9 +196,9 @@ describe('NetworkingEngine', /** @suppress {accessControls} */ () => { } catch (e) { expect(deferSpy.calls.count()).toBe(2); expect(deferSpy).toHaveBeenCalledWith(baseDelay, - jasmine.any(Function)); + jasmine.any(Function)); expect(deferSpy).toHaveBeenCalledWith(baseDelay * 2, - jasmine.any(Function)); + jasmine.any(Function)); } }); @@ -220,7 +220,7 @@ describe('NetworkingEngine', /** @suppress {accessControls} */ () => { // delay * (1 + 0.5) = baseDelay * (1 + 0.5) expect(deferSpy.calls.count()).toBe(1); expect(deferSpy).toHaveBeenCalledWith(baseDelay * 1.5, - jasmine.any(Function)); + jasmine.any(Function)); } }); }); // describe('backoff') @@ -989,13 +989,13 @@ describe('NetworkingEngine', /** @suppress {accessControls} */ () => { it('is called on recoverable error', async () => { const error1 = new shaka.util.Error( - shaka.util.Error.Severity.RECOVERABLE, - shaka.util.Error.Category.NETWORK, - shaka.util.Error.Code.HTTP_ERROR); + shaka.util.Error.Severity.RECOVERABLE, + shaka.util.Error.Category.NETWORK, + shaka.util.Error.Code.HTTP_ERROR); const error2 = new shaka.util.Error( - shaka.util.Error.Severity.RECOVERABLE, - shaka.util.Error.Category.NETWORK, - shaka.util.Error.Code.BAD_HTTP_STATUS); + shaka.util.Error.Severity.RECOVERABLE, + shaka.util.Error.Category.NETWORK, + shaka.util.Error.Code.BAD_HTTP_STATUS); const resolve = createResponse(); rejectScheme.and.callFake(() => { switch (rejectScheme.calls.count()) { diff --git a/test/offline/offline_manifest_parser_unit.js b/test/offline/offline_manifest_parser_unit.js index 2c731b546..aab7a4166 100644 --- a/test/offline/offline_manifest_parser_unit.js +++ b/test/offline/offline_manifest_parser_unit.js @@ -19,7 +19,7 @@ describe('OfflineManifestParser', () => { // The offline manifest parser does not need the player interface, so // this is a work around to avoid creating one. const playerInterface = - /** @type {shaka.extern.ManifestParser.PlayerInterface} */({}); + /** @type {shaka.extern.ManifestParser.PlayerInterface} */({}); // A session id that will be found in the manifest created by |makeManifest|. const sessionId = 'session-id'; diff --git a/test/offline/storage_unit.js b/test/offline/storage_unit.js index 8f2877238..f7d293110 100644 --- a/test/offline/storage_unit.js +++ b/test/offline/storage_unit.js @@ -131,65 +131,65 @@ describe('Storage', () => { // http://crbug.com/883895 quarantinedIt('removes persistent license', drmCheckAndRun(async () => { - const TestManifestParser = shaka.test.TestScheme.ManifestParser; + const TestManifestParser = shaka.test.TestScheme.ManifestParser; - // PART 1 - Download and store content that has a persistent license - // associated with it. - const stored = await storage.store( - 'test:sintel-enc', noMetadata, TestManifestParser); - expect(stored.offlineUri).toBeTruthy(); + // PART 1 - Download and store content that has a persistent license + // associated with it. + const stored = await storage.store( + 'test:sintel-enc', noMetadata, TestManifestParser); + expect(stored.offlineUri).toBeTruthy(); - /** @type {shaka.offline.OfflineUri} */ - const uri = shaka.offline.OfflineUri.parse(stored.offlineUri); - goog.asserts.assert(uri, 'Stored offline uri should be non-null'); + /** @type {shaka.offline.OfflineUri} */ + const uri = shaka.offline.OfflineUri.parse(stored.offlineUri); + goog.asserts.assert(uri, 'Stored offline uri should be non-null'); - const manifest = await getStoredManifest(uri); - expect(manifest.offlineSessionIds).toBeTruthy(); - expect(manifest.offlineSessionIds.length).toBeTruthy(); + const manifest = await getStoredManifest(uri); + expect(manifest.offlineSessionIds).toBeTruthy(); + expect(manifest.offlineSessionIds.length).toBeTruthy(); - // Work around http://crbug.com/887535 in which load cannot happen right - // after close. Experimentally, we seem to need a ~1s delay, so we're - // using a 3s delay to ensure it doesn't flake. Without this, we get - // error 6005 (FAILED_TO_CREATE_SESSION) with system code 70. - // TODO: Remove when Chrome is fixed - await shaka.test.Util.delay(3); + // Work around http://crbug.com/887535 in which load cannot happen right + // after close. Experimentally, we seem to need a ~1s delay, so we're + // using a 3s delay to ensure it doesn't flake. Without this, we get + // error 6005 (FAILED_TO_CREATE_SESSION) with system code 70. + // TODO: Remove when Chrome is fixed + await shaka.test.Util.delay(3); - // PART 2 - Check that the licences are stored. - await withDrm(player, manifest, (drm) => { - return Promise.all(manifest.offlineSessionIds.map(async (session) => { - const foundSession = await loadOfflineSession(drm, session); - expect(foundSession).toBeTruthy(); + // PART 2 - Check that the licences are stored. + await withDrm(player, manifest, (drm) => { + return Promise.all(manifest.offlineSessionIds.map(async (session) => { + const foundSession = await loadOfflineSession(drm, session); + expect(foundSession).toBeTruthy(); + })); + }); + + // PART 3 - Remove the manifest from storage. This should remove all the + // sessions. + await storage.remove(uri.toString()); + + // Work around http://crbug.com/887535 in which load cannot happen right + // after close. Experimentally, we seem to need a ~1s delay, so we're + // using a 3s delay to ensure it doesn't flake. Without this, we get + // error 6005 (FAILED_TO_CREATE_SESSION) with system code 70. + // TODO: Remove when Chrome is fixed + await shaka.test.Util.delay(3); + + // PART 4 - Check that the licenses were removed. + try { + await withDrm(player, manifest, (drm) => { + return Promise.all(manifest.offlineSessionIds.map(async (session) => { + const notFoundSession = await loadOfflineSession(drm, session); + // TODO: This is failing. The session is actually found, possibly + // due to http://crbug.com/690583, but this is unclear. + expect(notFoundSession).toBeFalsy(); + })); + }); + + throw new Error('Expected drm to throw OFFLINE_SESSION_REMOVED'); + } catch (e) { + expect(e).toBeTruthy(); + expect(e.code).toBe(shaka.util.Error.Code.OFFLINE_SESSION_REMOVED); + } })); - }); - - // PART 3 - Remove the manifest from storage. This should remove all the - // sessions. - await storage.remove(uri.toString()); - - // Work around http://crbug.com/887535 in which load cannot happen right - // after close. Experimentally, we seem to need a ~1s delay, so we're - // using a 3s delay to ensure it doesn't flake. Without this, we get - // error 6005 (FAILED_TO_CREATE_SESSION) with system code 70. - // TODO: Remove when Chrome is fixed - await shaka.test.Util.delay(3); - - // PART 4 - Check that the licenses were removed. - try { - await withDrm(player, manifest, (drm) => { - return Promise.all(manifest.offlineSessionIds.map(async (session) => { - const notFoundSession = await loadOfflineSession(drm, session); - // TODO: This is failing. The session is actually found, possibly - // due to http://crbug.com/690583, but this is unclear. - expect(notFoundSession).toBeFalsy(); - })); - }); - - throw new Error('Expected drm to throw OFFLINE_SESSION_REMOVED'); - } catch (e) { - expect(e).toBeTruthy(); - expect(e.code).toBe(shaka.util.Error.Code.OFFLINE_SESSION_REMOVED); - } - })); // TODO: Still failing in Chrome canary 73 on 2018-12-12. // Some combination of these bugs is preventing this test from working: @@ -199,84 +199,84 @@ describe('Storage', () => { // http://crbug.com/883895 quarantinedIt('defers removing licenses on error', drmCheckAndRun(async () => { - const TestManifestParser = shaka.test.TestScheme.ManifestParser; - const getEmeSessions = async () => { - /** @type {!shaka.offline.StorageMuxer} */ - const muxer = new shaka.offline.StorageMuxer(); - await muxer.init(); + const TestManifestParser = shaka.test.TestScheme.ManifestParser; + const getEmeSessions = async () => { + /** @type {!shaka.offline.StorageMuxer} */ + const muxer = new shaka.offline.StorageMuxer(); + await muxer.init(); - /** @type {!Array.<!Promise>} */ - const promises = []; - muxer.forEachEmeSessionCell((cell) => promises.push(cell.getAll())); - const cellByMechanism = await Promise.all(promises); - await muxer.destroy(); - return cellByMechanism.reduce(shaka.util.Functional.collapseArrays, []); - }; + /** @type {!Array.<!Promise>} */ + const promises = []; + muxer.forEachEmeSessionCell((cell) => promises.push(cell.getAll())); + const cellByMechanism = await Promise.all(promises); + await muxer.destroy(); + return cellByMechanism.reduce(shaka.util.Functional.collapseArrays, []); + }; - const oldSessions = await getEmeSessions(); - expect(oldSessions).toEqual([]); + const oldSessions = await getEmeSessions(); + expect(oldSessions).toEqual([]); - // PART 1 - Download and store content that has a persistent license - // associated with it. - const stored = await storage.store( - 'test:sintel-enc', noMetadata, TestManifestParser); - expect(stored.offlineUri).toBeTruthy(); + // PART 1 - Download and store content that has a persistent license + // associated with it. + const stored = await storage.store( + 'test:sintel-enc', noMetadata, TestManifestParser); + expect(stored.offlineUri).toBeTruthy(); - /** @type {shaka.offline.OfflineUri} */ - const uri = shaka.offline.OfflineUri.parse(stored.offlineUri); - goog.asserts.assert(uri, 'Stored offline uri should be non-null'); - const manifest = await getStoredManifest(uri); + /** @type {shaka.offline.OfflineUri} */ + const uri = shaka.offline.OfflineUri.parse(stored.offlineUri); + goog.asserts.assert(uri, 'Stored offline uri should be non-null'); + const manifest = await getStoredManifest(uri); - // PART 2 - Add an error so the release license message fails. - storage.getNetworkingEngine().registerRequestFilter((type, request) => { - if (type == shaka.net.NetworkingEngine.RequestType.LICENSE) { - throw new Error('Error should be ignored'); - } - }); + // PART 2 - Add an error so the release license message fails. + storage.getNetworkingEngine().registerRequestFilter((type, request) => { + if (type == shaka.net.NetworkingEngine.RequestType.LICENSE) { + throw new Error('Error should be ignored'); + } + }); - // PART 3 - Remove the manifest from storage. This should ignore the - // error with the EME session. It should also store the session for later - // removal. - await storage.remove(uri.toString()); + // PART 3 - Remove the manifest from storage. This should ignore the + // error with the EME session. It should also store the session for later + // removal. + await storage.remove(uri.toString()); - // PART 4 - Verify the media was deleted but the session still exists. - const storedContents = await storage.list(); - expect(storedContents).toEqual([]); + // PART 4 - Verify the media was deleted but the session still exists. + const storedContents = await storage.list(); + expect(storedContents).toEqual([]); - // TODO: Chrome has a bug that prevents loading the session a second time, - // so we can't check EME for the session. Instead, check the database. - // This can be changed when http://crbug.com/887635 is fixed. - // TODO: Whether checking the database or loading the EME session, this - // will fail because of another Chrome bug. Calling remove() causes the - // session to be removed without waiting for update. So this entire - // feature is non-functional on Chrome. The test can probably be made to - // pass once https://crbug.com/883895 is fixed, possibly after using a - // delay to work around http://crbug.com/887535 . - const sessions = await getEmeSessions(); - expect(sessions.length).toBeGreaterThan(0); + // TODO: Chrome has a bug that prevents loading the session a second time, + // so we can't check EME for the session. Instead, check the database. + // This can be changed when http://crbug.com/887635 is fixed. + // TODO: Whether checking the database or loading the EME session, this + // will fail because of another Chrome bug. Calling remove() causes the + // session to be removed without waiting for update. So this entire + // feature is non-functional on Chrome. The test can probably be made to + // pass once https://crbug.com/883895 is fixed, possibly after using a + // delay to work around http://crbug.com/887535 . + const sessions = await getEmeSessions(); + expect(sessions.length).toBeGreaterThan(0); - // PART 5 - Disable the error and remove the EME session. - storage.getNetworkingEngine().clearAllRequestFilters(); - const didRemoveAll = await storage.removeEmeSessions(); - expect(didRemoveAll).toBe(true); + // PART 5 - Disable the error and remove the EME session. + storage.getNetworkingEngine().clearAllRequestFilters(); + const didRemoveAll = await storage.removeEmeSessions(); + expect(didRemoveAll).toBe(true); - // PART 6 - Check that the licenses were removed. - const endSessions = await getEmeSessions(); - expect(endSessions).toEqual([]); - try { - await withDrm(player, manifest, (drm) => { - return Promise.all(manifest.offlineSessionIds.map(async (session) => { - const notFoundSession = await loadOfflineSession(drm, session); - expect(notFoundSession).toBeFalsy(); - })); - }); + // PART 6 - Check that the licenses were removed. + const endSessions = await getEmeSessions(); + expect(endSessions).toEqual([]); + try { + await withDrm(player, manifest, (drm) => { + return Promise.all(manifest.offlineSessionIds.map(async (session) => { + const notFoundSession = await loadOfflineSession(drm, session); + expect(notFoundSession).toBeFalsy(); + })); + }); - throw new Error('Expected drm to throw OFFLINE_SESSION_REMOVED'); - } catch (e) { - expect(e).toBeTruthy(); - expect(e.code).toBe(shaka.util.Error.Code.OFFLINE_SESSION_REMOVED); - } - })); + throw new Error('Expected drm to throw OFFLINE_SESSION_REMOVED'); + } catch (e) { + expect(e).toBeTruthy(); + expect(e.code).toBe(shaka.util.Error.Code.OFFLINE_SESSION_REMOVED); + } + })); }); describe('default track selection callback', () => { @@ -574,7 +574,7 @@ describe('Storage', () => { ]; const manifest = makeWithVariantBandwidth(); await runProgressTest(manifest, progressSteps); - })); + })); /** * Download |manifest| and make sure that the reported progress matches diff --git a/test/player_integration.js b/test/player_integration.js index 82bbcdcf7..9ef3f9912 100644 --- a/test/player_integration.js +++ b/test/player_integration.js @@ -266,7 +266,7 @@ describe('Player', () => { const partialUri = new goog.Uri('/base/test/test/assets/text-clip.vtt'); const absoluteUri = locationUri.resolve(partialUri); await player.addTextTrack(absoluteUri.toString(), 'en', 'subtitles', - 'text/vtt'); + 'text/vtt'); const textTracks = player.getTextTracks(); expect(textTracks).toBeTruthy(); @@ -646,17 +646,17 @@ describe('Player Load Path', () => { it('attach and initialize media source when constructed with media element', async () => { - expect(video.src).toBeFalsy(); + expect(video.src).toBeFalsy(); - createPlayer(/* attachedTo= */ video); + createPlayer(/* attachedTo= */ video); - // Wait until we enter the media source state. - await new Promise((resolve) => { - whenEnteringState('media-source', resolve); - }); + // Wait until we enter the media source state. + await new Promise((resolve) => { + whenEnteringState('media-source', resolve); + }); - expect(video.src).toBeTruthy(); - }); + expect(video.src).toBeTruthy(); + }); it('does not set video.src when no video is provided', async () => { expect(video.src).toBeFalsy(); @@ -672,43 +672,43 @@ describe('Player Load Path', () => { it('attach + initializeMediaSource=true will initialize media source', async () => { - createPlayer(/* attachedTo= */ null); + createPlayer(/* attachedTo= */ null); - expect(video.src).toBeFalsy(); - await player.attach(video, /* initializeMediaSource= */ true); - expect(video.src).toBeTruthy(); - }); + expect(video.src).toBeFalsy(); + await player.attach(video, /* initializeMediaSource= */ true); + expect(video.src).toBeTruthy(); + }); it('attach + initializeMediaSource=false will not intialize media source', async () => { - createPlayer(/* attachedTo= */ null); + createPlayer(/* attachedTo= */ null); - expect(video.src).toBeFalsy(); - await player.attach(video, /* initializeMediaSource= */ false); - expect(video.src).toBeFalsy(); - }); + expect(video.src).toBeFalsy(); + await player.attach(video, /* initializeMediaSource= */ false); + expect(video.src).toBeFalsy(); + }); it('unload + initializeMediaSource=false does not initialize media source', async () => { - createPlayer(/* attachedTo= */ null); + createPlayer(/* attachedTo= */ null); - await player.attach(video); - await player.load('test:sintel'); + await player.attach(video); + await player.load('test:sintel'); - await player.unload(/* initializeMediaSource= */ false); - expect(video.src).toBeFalsy(); - }); + await player.unload(/* initializeMediaSource= */ false); + expect(video.src).toBeFalsy(); + }); it('unload + initializeMediaSource=true initializes media source', async () => { - createPlayer(/* attachedTo= */ null); + createPlayer(/* attachedTo= */ null); - await player.attach(video); - await player.load('test:sintel'); + await player.attach(video); + await player.load('test:sintel'); - await player.unload(/* initializeMediaSource= */ true); - expect(video.src).toBeTruthy(); - }); + await player.unload(/* initializeMediaSource= */ true); + expect(video.src).toBeTruthy(); + }); // There was a bug when calling unload before calling load would cause // the load to continue before the (first) unload was complete. @@ -961,29 +961,29 @@ describe('Player Load Path', () => { // pre-initialize media source engine, we do not re-create the media source // instance when loading. it('pre-initialized media source is used when player continues loading', - async () => { - createPlayer(/* attachedTo= */ null); + async () => { + createPlayer(/* attachedTo= */ null); - // After we attach and initialize media source, we should just see - // two states in our history. - await player.attach(video, /* initializeMediaSource= */ true); - expect(getVisitedStates()).toEqual([ - 'attach', - 'media-source', - ]); + // After we attach and initialize media source, we should just see + // two states in our history. + await player.attach(video, /* initializeMediaSource= */ true); + expect(getVisitedStates()).toEqual([ + 'attach', + 'media-source', + ]); - // When we load, the only change in the visited states should be that - // we added "load". - await player.load('test:sintel'); - expect(getVisitedStates()).toEqual([ - 'attach', - 'media-source', - 'manifest-parser', - 'manifest', - 'drm-engine', - 'load', - ]); - }); + // When we load, the only change in the visited states should be that + // we added "load". + await player.load('test:sintel'); + expect(getVisitedStates()).toEqual([ + 'attach', + 'media-source', + 'manifest-parser', + 'manifest', + 'drm-engine', + 'load', + ]); + }); // We want to make sure that we can interrupt the load process at key-points // in time. After each node in the graph, we should be able to reroute and do diff --git a/test/player_src_equals_external.js b/test/player_src_equals_external.js index c17f8fcd5..1a690fdca 100644 --- a/test/player_src_equals_external.js +++ b/test/player_src_equals_external.js @@ -19,10 +19,10 @@ describe('Player Src Equals', () => { // This asset needs to be (1) long and (2) high bitrate so that we can // invoke unbuffered seeks. const LARGE_MP4_CONTENT_URI = [ - 'https://storage.googleapis.com', - 'shaka-demo-assets', - 'sintel-mp4-only', - 'v-2160p-17000k-libx264.mp4', + 'https://storage.googleapis.com', + 'shaka-demo-assets', + 'sintel-mp4-only', + 'v-2160p-17000k-libx264.mp4', ].join('/'); /** @type {!HTMLVideoElement} */ diff --git a/test/player_unit.js b/test/player_unit.js index 45dcca327..8b2fdecd1 100644 --- a/test/player_unit.js +++ b/test/player_unit.js @@ -1769,7 +1769,7 @@ describe('Player', () => { const lang = languages[i]; if (lang.charAt(0) == '*') { generator - .addVariant(i) + .addVariant(i) .primary() .language(lang.substr(1)) .addAudio(i); @@ -2171,25 +2171,25 @@ describe('Player', () => { it('throw CONTENT_UNSUPPORTED_BY_BROWSER when the only period is ' + 'unplayable', async () => { - manifest = new shaka.test.ManifestGenerator() - .addPeriod(0) - .addVariant(0).bandwidth(500) - .addVideo(0).mime('video/mp4', 'bad') - .build(); - const parser = new shaka.test.FakeManifestParser(manifest); - const factory = () => parser; - try { - await player.load(fakeManifestUri, 0, factory); - fail(); - } catch (error) { - shaka.test.Util.expectToEqualError( - error, - new shaka.util.Error( - shaka.util.Error.Severity.CRITICAL, - shaka.util.Error.Category.MANIFEST, - shaka.util.Error.Code.CONTENT_UNSUPPORTED_BY_BROWSER)); - } - }); + manifest = new shaka.test.ManifestGenerator() + .addPeriod(0) + .addVariant(0).bandwidth(500) + .addVideo(0).mime('video/mp4', 'bad') + .build(); + const parser = new shaka.test.FakeManifestParser(manifest); + const factory = () => parser; + try { + await player.load(fakeManifestUri, 0, factory); + fail(); + } catch (error) { + shaka.test.Util.expectToEqualError( + error, + new shaka.util.Error( + shaka.util.Error.Severity.CRITICAL, + shaka.util.Error.Category.MANIFEST, + shaka.util.Error.Code.CONTENT_UNSUPPORTED_BY_BROWSER)); + } + }); it('throw CONTENT_UNSUPPORTED_BY_BROWSER when all periods are unplayable', async () => { diff --git a/test/routing/walker_unit.js b/test/routing/walker_unit.js index d8d1cd1c8..a2b2631da 100644 --- a/test/routing/walker_unit.js +++ b/test/routing/walker_unit.js @@ -30,13 +30,13 @@ describe('Walker', () => { uri: null, }; - // The graph topology that we will be using for our tests. - // - // [ A ] ---> [ B ] ---> [ E ] - // ^ | - // | v - // [ D ] <--- [ C ] - // + // The graph topology that we will be using for our tests. + // + // [ A ] ---> [ B ] ---> [ E ] + // ^ | + // | v + // [ D ] <--- [ C ] + // /** @type {shaka.routing.Node} */ const nodeA = {name: 'a'}; /** @type {shaka.routing.Node} */ diff --git a/test/test/boot.js b/test/test/boot.js index 7f54ce896..1321cc55b 100644 --- a/test/test/boot.js +++ b/test/test/boot.js @@ -199,19 +199,19 @@ function getClientArg(name) { // Load required AMD modules, then proceed with tests. require(['promise-mock', 'sprintf-js', 'less'], (PromiseMock, sprintfJs, less) => { - window.PromiseMock = PromiseMock; - window.sprintf = sprintfJs.sprintf; - window.less = less; + window.PromiseMock = PromiseMock; + window.sprintf = sprintfJs.sprintf; + window.less = less; - // Patch a new convenience method into PromiseMock. - // See https://github.com/taylorhakes/promise-mock/issues/7 - PromiseMock.flush = () => { - // Pass strict == false so it does not throw. - PromiseMock.runAll(false /* strict */); - }; + // Patch a new convenience method into PromiseMock. + // See https://github.com/taylorhakes/promise-mock/issues/7 + PromiseMock.flush = () => { + // Pass strict == false so it does not throw. + PromiseMock.runAll(false /* strict */); + }; - done(); - }); + done(); + }); }); const originalSetTimeout = window.setTimeout; diff --git a/test/test/util/canned_idb.js b/test/test/util/canned_idb.js index a3894d13a..f4b973835 100644 --- a/test/test/util/canned_idb.js +++ b/test/test/util/canned_idb.js @@ -228,7 +228,7 @@ shaka.test.CannedIDB = class { await op.promise(); shaka.log.debug('Dumped', savedStore.data.length, 'entries from store', - name); + name); savedDatabase.stores[name] = savedStore; } @@ -268,7 +268,7 @@ shaka.test.CannedIDB = class { request.onupgradeneeded = (event) => { shaka.log.debug('DB upgrade from', event.oldVersion, 'to', - savedDatabase.version); + savedDatabase.version); const transaction = event.target.transaction; const db = transaction.db; @@ -325,7 +325,7 @@ shaka.test.CannedIDB = class { const storeInfo = savedDatabase.stores[storeName]; shaka.log.debug('Populating store', storeName, 'with', - storeInfo.data.length, 'entries'); + storeInfo.data.length, 'entries'); storeInfo.data.forEach((item) => { // If this store uses an explicit keyPath, we can't specify a key. if (storeInfo.parameters.keyPath) { diff --git a/test/test/util/dash_parser_util.js b/test/test/util/dash_parser_util.js index f6cf09c0e..433bad250 100644 --- a/test/test/util/dash_parser_util.js +++ b/test/test/util/dash_parser_util.js @@ -99,31 +99,31 @@ shaka.test.Dash.testFails = async function(manifestText, expectedError) { */ shaka.test.Dash.makeSimpleManifestText = function(lines, duration, startTime) { - let periodAttr = ''; - let mpdAttr = 'type="dynamic" availabilityStartTime="1970-01-01T00:00:00Z"'; - if (duration) { - periodAttr = 'duration="PT' + duration + 'S"'; - mpdAttr = 'type="static"'; - } - if (startTime) { - periodAttr += ' start="PT' + startTime + 'S"'; - } + let periodAttr = ''; + let mpdAttr = 'type="dynamic" availabilityStartTime="1970-01-01T00:00:00Z"'; + if (duration) { + periodAttr = 'duration="PT' + duration + 'S"'; + mpdAttr = 'type="static"'; + } + if (startTime) { + periodAttr += ' start="PT' + startTime + 'S"'; + } - const start = [ - '<MPD ' + mpdAttr + '>', - ' <Period ' + periodAttr + '>', - ' <AdaptationSet mimeType="video/mp4">', - ' <Representation bandwidth="500">', - ' <BaseURL>http://example.com</BaseURL>', - ]; - const end = [ - ' </Representation>', - ' </AdaptationSet>', - ' </Period>', - '</MPD>', - ]; - return start.concat(lines, end).join('\n'); -}; + const start = [ + '<MPD ' + mpdAttr + '>', + ' <Period ' + periodAttr + '>', + ' <AdaptationSet mimeType="video/mp4">', + ' <Representation bandwidth="500">', + ' <BaseURL>http://example.com</BaseURL>', + ]; + const end = [ + ' </Representation>', + ' </AdaptationSet>', + ' </Period>', + '</MPD>', + ]; + return start.concat(lines, end).join('\n'); + }; /** diff --git a/test/test/util/fake_media_source_engine.js b/test/test/util/fake_media_source_engine.js index ab41b2b31..00801ae4d 100644 --- a/test/test/util/fake_media_source_engine.js +++ b/test/test/util/fake_media_source_engine.js @@ -86,43 +86,43 @@ shaka.test.FakeMediaSourceEngine = function(segmentData, drift) { /** @type {!jasmine.Spy} */ this.setDuration = jasmine.createSpy('setDuration') - .and.callFake(this.setDurationImpl_.bind(this)); + .and.callFake(this.setDurationImpl_.bind(this)); /** @type {!jasmine.Spy} */ this.getDuration = jasmine.createSpy('getDuration') - .and.callFake(this.getDurationImpl_.bind(this)); + .and.callFake(this.getDurationImpl_.bind(this)); /** @type {!jasmine.Spy} */ this.appendBuffer = jasmine.createSpy('appendBuffer') - .and.callFake(this.appendBufferImpl.bind(this)); + .and.callFake(this.appendBufferImpl.bind(this)); /** @type {!jasmine.Spy} */ this.clear = jasmine.createSpy('clear') - .and.callFake(this.clearImpl_.bind(this)); + .and.callFake(this.clearImpl_.bind(this)); /** @type {!jasmine.Spy} */ this.bufferStart = jasmine.createSpy('bufferStart') - .and.callFake(this.bufferStartImpl_.bind(this)); + .and.callFake(this.bufferStartImpl_.bind(this)); /** @type {!jasmine.Spy} */ this.bufferEnd = jasmine.createSpy('bufferEnd') - .and.callFake(this.bufferEndImpl_.bind(this)); + .and.callFake(this.bufferEndImpl_.bind(this)); /** @type {!jasmine.Spy} */ this.isBuffered = jasmine.createSpy('isBuffered') - .and.callFake(this.isBufferedImpl_.bind(this)); + .and.callFake(this.isBufferedImpl_.bind(this)); /** @type {!jasmine.Spy} */ this.bufferedAheadOf = jasmine.createSpy('bufferedAheadOf') - .and.callFake(this.bufferedAheadOfImpl.bind(this)); + .and.callFake(this.bufferedAheadOfImpl.bind(this)); /** @type {!jasmine.Spy} */ this.setStreamProperties = jasmine.createSpy('setStreamProperties') - .and.callFake(this.setStreamPropertiesImpl_.bind(this)); + .and.callFake(this.setStreamPropertiesImpl_.bind(this)); /** @type {!jasmine.Spy} */ this.remove = jasmine.createSpy('remove') - .and.callFake(this.removeImpl.bind(this)); + .and.callFake(this.removeImpl.bind(this)); /** @type {!jasmine.Spy} */ this.flush = jasmine.createSpy('flush').and.returnValue(Promise.resolve()); @@ -207,18 +207,18 @@ shaka.test.FakeMediaSourceEngine.prototype.bufferEndImpl_ = function(type) { */ shaka.test.FakeMediaSourceEngine.prototype.isBufferedImpl_ = function(type, time) { - if (this.segments[type] === undefined) { - throw new Error('unexpected type'); - } + if (this.segments[type] === undefined) { + throw new Error('unexpected type'); + } - const first = this.segments[type].indexOf(true); - const last = this.segments[type].lastIndexOf(true); - if (first < 0 || last < 0) { - return false; - } + const first = this.segments[type].indexOf(true); + const last = this.segments[type].lastIndexOf(true); + if (first < 0 || last < 0) { + return false; + } - return time >= this.toTime_(type, first) && time < this.toTime_(type, last); -}; + return time >= this.toTime_(type, first) && time < this.toTime_(type, last); + }; /** @@ -283,7 +283,7 @@ shaka.test.FakeMediaSourceEngine.prototype.appendBufferImpl = function( // 'trickvideo' value is only used for testing. // Cast to the ContentType enum for compatibility. type = /** @type {shaka.util.ManifestParserUtils.ContentType} */( - 'trickvideo'); + 'trickvideo'); } } if (i >= 0) { @@ -306,7 +306,7 @@ shaka.test.FakeMediaSourceEngine.prototype.appendBufferImpl = function( // 'trickvideo' value is only used for testing. // Cast to the ContentType enum for compatibility. type = /** @type {shaka.util.ManifestParserUtils.ContentType} */( - 'trickvideo'); + 'trickvideo'); } } if (i < 0) { @@ -339,31 +339,31 @@ shaka.test.FakeMediaSourceEngine.prototype.appendBufferImpl = function( */ shaka.test.FakeMediaSourceEngine.prototype.removeImpl = function(type, start, end) { - if (this.segments[type] === undefined) { - throw new Error('unexpected type'); - } + if (this.segments[type] === undefined) { + throw new Error('unexpected type'); + } - const first = this.toIndex_(type, start); - if (first < 0 || first >= this.segments[type].length) { - throw new Error('unexpected start'); - } + const first = this.toIndex_(type, start); + if (first < 0 || first >= this.segments[type].length) { + throw new Error('unexpected start'); + } - // Note: |end| is exclusive. - const last = this.toIndex_(type, end - 0.000001); - if (last < 0) { - throw new Error('unexpected end'); - } + // Note: |end| is exclusive. + const last = this.toIndex_(type, end - 0.000001); + if (last < 0) { + throw new Error('unexpected end'); + } - if (first > last) { - throw new Error('unexpected start and end'); - } + if (first > last) { + throw new Error('unexpected start and end'); + } - for (let i = first; i <= last; ++i) { - this.segments[type][i] = false; - } + for (let i = first; i <= last; ++i) { + this.segments[type][i] = false; + } - return Promise.resolve(); -}; + return Promise.resolve(); + }; /** @@ -388,7 +388,7 @@ shaka.test.FakeMediaSourceEngine.prototype.clearImpl_ = function(type) { // Cast to the ContentType enum for compatibility. this.clearImpl_( /** @type {shaka.util.ManifestParserUtils.ContentType} */( - 'trickvideo')); + 'trickvideo')); } return Promise.resolve(); diff --git a/test/test/util/manifest_generator.js b/test/test/util/manifest_generator.js index 03312adea..d576e51ce 100644 --- a/test/test/util/manifest_generator.js +++ b/test/test/util/manifest_generator.js @@ -287,10 +287,10 @@ shaka.test.ManifestGenerator.prototype.licenseServerUri = function(uri) { */ shaka.test.ManifestGenerator.prototype.distinctiveIdentifierRequired = function() { - const drmInfo = this.currentDrmInfo_(); - drmInfo.distinctiveIdentifierRequired = true; - return this; -}; + const drmInfo = this.currentDrmInfo_(); + drmInfo.distinctiveIdentifierRequired = true; + return this; + }; /** @@ -482,7 +482,7 @@ shaka.test.ManifestGenerator.prototype.addPartialStream = function(type, id) { this.lastStreamAdded_ = stream; const streamObj = - /** @type {shaka.extern.Stream} */ (jasmine.objectContaining(stream)); + /** @type {shaka.extern.Stream} */ (jasmine.objectContaining(stream)); if (type == ContentType.TEXT) { const period = this.currentPeriod_(); period.textStreams.push(streamObj); @@ -510,60 +510,60 @@ shaka.test.ManifestGenerator.prototype.addPartialStream = function(type, id) { */ shaka.test.ManifestGenerator.prototype.createStream_ = function(id, type, language) { - goog.asserts.assert(!this.isIdUsed_(id), - 'Streams should have unique ids!'); + goog.asserts.assert(!this.isIdUsed_(id), + 'Streams should have unique ids!'); - const ContentType = shaka.util.ManifestParserUtils.ContentType; - let defaultMimeType = 'text/plain'; - let defaultCodecs = ''; + const ContentType = shaka.util.ManifestParserUtils.ContentType; + let defaultMimeType = 'text/plain'; + let defaultCodecs = ''; - if (type == ContentType.AUDIO) { - defaultMimeType = 'audio/mp4'; - defaultCodecs = 'mp4a.40.2'; - } else if (type == ContentType.VIDEO) { - defaultMimeType = 'video/mp4'; - defaultCodecs = 'avc1.4d401f'; - } else if (type == ContentType.TEXT) { - defaultMimeType = 'text/vtt'; - } + if (type == ContentType.AUDIO) { + defaultMimeType = 'audio/mp4'; + defaultCodecs = 'mp4a.40.2'; + } else if (type == ContentType.VIDEO) { + defaultMimeType = 'video/mp4'; + defaultCodecs = 'avc1.4d401f'; + } else if (type == ContentType.TEXT) { + defaultMimeType = 'text/vtt'; + } - const create = + const create = jasmine.createSpy('createSegmentIndex').and.callFake(() => { return Promise.resolve(); }); - const find = jasmine.createSpy('findSegmentPosition').and.returnValue(null); - const get = jasmine.createSpy('getSegmentReference').and.returnValue(null); + const find = jasmine.createSpy('findSegmentPosition').and.returnValue(null); + const get = jasmine.createSpy('getSegmentReference').and.returnValue(null); - /** @type {shaka.extern.Stream} */ - const stream = { - id: id, - originalId: null, - createSegmentIndex: shaka.test.Util.spyFunc(create), - findSegmentPosition: shaka.test.Util.spyFunc(find), - getSegmentReference: shaka.test.Util.spyFunc(get), - initSegmentReference: null, - presentationTimeOffset: 0, - mimeType: defaultMimeType, - codecs: defaultCodecs, - frameRate: undefined, - bandwidth: undefined, - width: undefined, - height: undefined, - kind: undefined, - encrypted: false, - keyId: null, - language: language, - label: null, - type: type, - primary: false, - trickModeVideo: null, - emsgSchemeIdUris: null, - roles: [], - channelsCount: null, - closedCaptions: null, - }; - return stream; -}; + /** @type {shaka.extern.Stream} */ + const stream = { + id: id, + originalId: null, + createSegmentIndex: shaka.test.Util.spyFunc(create), + findSegmentPosition: shaka.test.Util.spyFunc(find), + getSegmentReference: shaka.test.Util.spyFunc(get), + initSegmentReference: null, + presentationTimeOffset: 0, + mimeType: defaultMimeType, + codecs: defaultCodecs, + frameRate: undefined, + bandwidth: undefined, + width: undefined, + height: undefined, + kind: undefined, + encrypted: false, + keyId: null, + language: language, + label: null, + type: type, + primary: false, + trickModeVideo: null, + emsgSchemeIdUris: null, + roles: [], + channelsCount: null, + closedCaptions: null, + }; + return stream; + }; /** @@ -610,7 +610,7 @@ shaka.test.ManifestGenerator.prototype.textStream = function(uri) { stream.createSegmentIndex = () => Promise.resolve(); stream.findSegmentPosition = (time) => - (time >= 0 && time < duration ? 1 : null); + (time >= 0 && time < duration ? 1 : null); stream.getSegmentReference = (position) => { if (position != 1) { return null; @@ -644,8 +644,8 @@ shaka.test.ManifestGenerator.prototype.delayCreateSegmentIndex = function() { shaka.test.ManifestGenerator.prototype.anyInitSegment = function() { const stream = this.currentStream_(); stream.initSegmentReference = - /** @type {shaka.media.InitSegmentReference} */ ( - jasmine.any(this.shaka_.media.InitSegmentReference)); + /** @type {shaka.media.InitSegmentReference} */ ( + jasmine.any(this.shaka_.media.InitSegmentReference)); return this; }; @@ -716,10 +716,10 @@ shaka.test.ManifestGenerator.prototype.mime = function(mime, codecs) { */ shaka.test.ManifestGenerator.prototype.closedCaptions = function(closedCaptions) { - const stream = this.currentStream_(); - stream.closedCaptions = closedCaptions; - return this; -}; + const stream = this.currentStream_(); + stream.closedCaptions = closedCaptions; + return this; + }; /** @@ -847,7 +847,7 @@ shaka.test.ManifestGenerator.prototype.originalId = function(originalId) { */ shaka.test.ManifestGenerator.prototype.currentPeriod_ = function() { goog.asserts.assert(this.manifest_.periods.length > 0, - 'Must call addPeriod() at least once.'); + 'Must call addPeriod() at least once.'); return this.manifest_.periods[this.manifest_.periods.length - 1]; }; @@ -861,7 +861,7 @@ shaka.test.ManifestGenerator.prototype.currentVariant_ = function() { const realObj_ = shaka.test.ManifestGenerator.realObj_; const period = this.currentPeriod_(); goog.asserts.assert(period.variants.length > 0, - 'Must call addVariant() at least once.'); + 'Must call addVariant() at least once.'); return realObj_(period.variants[period.variants.length - 1]); }; @@ -873,7 +873,7 @@ shaka.test.ManifestGenerator.prototype.currentVariant_ = function() { */ shaka.test.ManifestGenerator.prototype.currentStreamOrVariant_ = function() { goog.asserts.assert(this.lastObjectAdded_, - 'Must call addVariant() or addTextStream()' + + 'Must call addVariant() or addTextStream()' + ' at least once.'); return this.lastObjectAdded_; }; @@ -888,7 +888,7 @@ shaka.test.ManifestGenerator.prototype.currentDrmInfo_ = function() { const realObj_ = shaka.test.ManifestGenerator.realObj_; const variant = this.currentVariant_(); goog.asserts.assert(variant.drmInfos.length > 0, - 'Must call addDrmInfo() at least once.'); + 'Must call addDrmInfo() at least once.'); return realObj_(variant.drmInfos[variant.drmInfos.length - 1]); }; @@ -900,7 +900,7 @@ shaka.test.ManifestGenerator.prototype.currentDrmInfo_ = function() { */ shaka.test.ManifestGenerator.prototype.currentStream_ = function() { goog.asserts.assert(this.lastStreamAdded_, - 'Must add at least one stream.'); + 'Must add at least one stream.'); return this.lastStreamAdded_; }; diff --git a/test/test/util/manifest_parser_util.js b/test/test/util/manifest_parser_util.js index 70821559a..37b321378 100644 --- a/test/test/util/manifest_parser_util.js +++ b/test/test/util/manifest_parser_util.js @@ -76,8 +76,8 @@ shaka.test.ManifestParser.verifySegmentIndex = function(stream, references) { */ shaka.test.ManifestParser.makeReference = function(uri, position, start, end, baseUri = '', - startByte = 0, endByte = null) { - const getUris = () => [baseUri + uri]; - return new shaka.media.SegmentReference( - position, start, end, getUris, startByte, endByte); -}; + startByte = 0, endByte = null) { + const getUris = () => [baseUri + uri]; + return new shaka.media.SegmentReference( + position, start, end, getUris, startByte, endByte); + }; diff --git a/test/test/util/offline_utils.js b/test/test/util/offline_utils.js index 8c59d25ad..6fac2ce80 100644 --- a/test/test/util/offline_utils.js +++ b/test/test/util/offline_utils.js @@ -84,7 +84,7 @@ shaka.test.OfflineUtils.createSegmentData = function(data) { * @param {shaka.extern.SegmentDataDB} expected */ shaka.test.OfflineUtils.expectSegmentsToContain = function(segments, - expected) { + expected) { const actualData = segments.map((segment) => { expect(segment.data).toBeTruthy(); return new Uint8Array(segment.data); diff --git a/test/test/util/stream_generator.js b/test/test/util/stream_generator.js index 27e629529..99043b4bf 100644 --- a/test/test/util/stream_generator.js +++ b/test/test/util/stream_generator.js @@ -188,7 +188,7 @@ shaka.test.Mp4VodStreamGenerator.prototype.init = function() { return Promise.all(async).then( (results) => { goog.asserts.assert(results.length == 2, - 'did not load both segments'); + 'did not load both segments'); this.initSegment_ = results[0]; this.segmentTemplate_ = results[1]; this.timescale_ = shaka.test.StreamGenerator.getTimescale_( @@ -218,7 +218,7 @@ shaka.test.Mp4VodStreamGenerator.prototype.getSegment = function( // |position| must be an integer and >= 1. goog.asserts.assert((position % 1 === 0) && (position >= 1), - 'segment number must be an integer >= 1'); + 'segment number must be an integer >= 1'); const segmentStartTime = (position - 1) * this.segmentDuration_; @@ -327,7 +327,7 @@ shaka.test.Mp4LiveStreamGenerator.prototype.init = function() { return Promise.all(async).then( (results) => { goog.asserts.assert(results.length == 2, - 'did not load both segments'); + 'did not load both segments'); this.initSegment_ = results[0]; this.segmentTemplate_ = results[1]; this.timescale_ = shaka.test.StreamGenerator.getTimescale_( @@ -358,7 +358,7 @@ shaka.test.Mp4LiveStreamGenerator.prototype.getSegment = function( // |position| must be an integer and >= 1. goog.asserts.assert((position % 1 === 0) && (position >= 1), - 'segment number must be an integer >= 1'); + 'segment number must be an integer >= 1'); const segmentStartTime = (position - 1) * this.segmentDuration_; @@ -466,7 +466,7 @@ shaka.test.StreamGenerator.getTimescale_ = function( shaka.test.StreamGenerator.setBaseMediaDecodeTime_ = function( segment, tfdtOffset, baseMediaDecodeTime, timescale) { goog.asserts.assert(baseMediaDecodeTime * timescale < Math.pow(2, 32), - 'Specied baseMediaDecodeTime is too big.'); + 'Specied baseMediaDecodeTime is too big.'); // NOTE from Microsoft on the lack of ArrayBuffer.prototype.slice in IE11: // "At this time we do not plan to fix this issue." ~ https://bit.ly/2ywEkpQ diff --git a/test/test/util/test_scheme.js b/test/test/util/test_scheme.js index b0b1d3559..74a16f8ed 100644 --- a/test/test/util/test_scheme.js +++ b/test/test/util/test_scheme.js @@ -420,13 +420,13 @@ shaka.test.TestScheme.createManifests = function(shaka, suffix) { */ function addStreamInfo(manifestGenerator, data, contentType, name) { manifestGenerator - .presentationTimeOffset(data[contentType].presentationTimeOffset) - .mime(data[contentType].mimeType, data[contentType].codecs) - .initSegmentReference( + .presentationTimeOffset(data[contentType].presentationTimeOffset) + .mime(data[contentType].mimeType, data[contentType].codecs) + .initSegmentReference( ['test:' + name + '/' + contentType + '/init'], 0, null) - .useSegmentTemplate('test:' + name + '/' + contentType + '/%d', - data[contentType].segmentDuration) - .closedCaptions(data[contentType].closedCaptions); + .useSegmentTemplate('test:' + name + '/' + contentType + '/%d', + data[contentType].segmentDuration) + .closedCaptions(data[contentType].closedCaptions); if (data[contentType].language) { manifestGenerator.language(data[contentType].language); @@ -493,8 +493,8 @@ shaka.test.TestScheme.createManifests = function(shaka, suffix) { if (data.text) { gen.addTextStream(3) - .mime(data.text.mimeType, data.text.codecs) - .textStream(getAbsoluteUri(data)); + .mime(data.text.mimeType, data.text.codecs) + .textStream(getAbsoluteUri(data)); if (data.text.language) { gen.language(data.text.language); @@ -560,14 +560,14 @@ shaka.test.TestScheme.createManifests = function(shaka, suffix) { addStreamInfo(gen, data, ContentType.AUDIO, 'sintel'); gen.addTextStream(idCount++) - .mime(data.text.mimeType, data.text.codecs) - .textStream(getAbsoluteUri(data)) - .language('zh'); + .mime(data.text.mimeType, data.text.codecs) + .textStream(getAbsoluteUri(data)) + .language('zh'); gen.addTextStream(idCount++) - .mime(data.text.mimeType, data.text.codecs) - .textStream(getAbsoluteUri(data)) - .language('fr'); + .mime(data.text.mimeType, data.text.codecs) + .textStream(getAbsoluteUri(data)) + .language('fr'); MANIFESTS['sintel_multi_lingual_multi_res' + suffix] = gen.build(); @@ -595,30 +595,30 @@ shaka.test.TestScheme.ManifestParser.prototype.configure = function(config) {}; /** @override */ shaka.test.TestScheme.ManifestParser.prototype.start = function(uri, playerInterface) { - const re = /^test:([^/]+)$/; - const manifestParts = re.exec(uri); - if (!manifestParts) { - // Use expect so the URI is printed on errors. - expect(uri).toMatch(re); - return Promise.reject(); - } + const re = /^test:([^/]+)$/; + const manifestParts = re.exec(uri); + if (!manifestParts) { + // Use expect so the URI is printed on errors. + expect(uri).toMatch(re); + return Promise.reject(); + } - const manifest = shaka.test.TestScheme.MANIFESTS[manifestParts[1]]; - expect(manifest).toBeTruthy(); - if (!manifest) { - return Promise.reject(); - } + const manifest = shaka.test.TestScheme.MANIFESTS[manifestParts[1]]; + expect(manifest).toBeTruthy(); + if (!manifest) { + return Promise.reject(); + } - // Invoke filtering interfaces similar to how a real parser would. - // This makes sure the filtering functions are covered implicitly by tests. - // This covers regression https://github.com/google/shaka-player/issues/988 - playerInterface.filterAllPeriods(manifest.periods); - manifest.periods.forEach((period) => { - playerInterface.filterNewPeriod(period); - }); + // Invoke filtering interfaces similar to how a real parser would. + // This makes sure the filtering functions are covered implicitly by tests. + // This covers regression https://github.com/google/shaka-player/issues/988 + playerInterface.filterAllPeriods(manifest.periods); + manifest.periods.forEach((period) => { + playerInterface.filterNewPeriod(period); + }); - return Promise.resolve(manifest); -}; + return Promise.resolve(manifest); + }; /** @override */ diff --git a/test/test/util/util.js b/test/test/util/util.js index ab613649b..df31436b2 100644 --- a/test/test/util/util.js +++ b/test/test/util/util.js @@ -335,7 +335,7 @@ shaka.test.Util.setupCSS = async function(cssLink) { // stylesheet, so LESS can process it. less.registerStylesheetsImmediately(); await less.refresh(/* reload */ true, - /* modifyVars*/ false, /* clearFileCache */ false); + /* modifyVars*/ false, /* clearFileCache */ false); }; /** @@ -379,54 +379,54 @@ shaka.test.Util.cleanupUI = async function() { */ shaka.test.Util.waitForMovementOrFailOnTimeout = (eventManager, target, timeout) => { - // TODO: Refactor all the wait utils into a class that avoids repeated args - const timeGoal = target.currentTime + 1; - let goalMet = false; - const startTime = Date.now(); - console.assert(!target.ended, 'Video should not be ended!'); - shaka.log.info('Waiting for movement from', target.currentTime, - 'to', timeGoal); + // TODO: Refactor all the wait utils into a class that avoids repeated args + const timeGoal = target.currentTime + 1; + let goalMet = false; + const startTime = Date.now(); + console.assert(!target.ended, 'Video should not be ended!'); + shaka.log.info('Waiting for movement from', target.currentTime, + 'to', timeGoal); - return new Promise((resolve, reject) => { - eventManager.listen(target, 'timeupdate', () => { - if (target.currentTime >= timeGoal || target.ended) { - goalMet = true; - const endTime = Date.now(); - const seconds = ((endTime - startTime) / 1000).toFixed(2); - shaka.log.info('Movement goal met after ' + seconds + ' seconds'); + return new Promise((resolve, reject) => { + eventManager.listen(target, 'timeupdate', () => { + if (target.currentTime >= timeGoal || target.ended) { + goalMet = true; + const endTime = Date.now(); + const seconds = ((endTime - startTime) / 1000).toFixed(2); + shaka.log.info('Movement goal met after ' + seconds + ' seconds'); - eventManager.unlisten(target, 'timeupdate'); - resolve(); - } - }); + eventManager.unlisten(target, 'timeupdate'); + resolve(); + } + }); - shaka.test.Util.delay(timeout).then(() => { - // This check is only necessary to supress the error log. It's fine to - // unlisten twice or to reject after resolve. Neither of those actions - // matter. But the error log can be confusing during debugging if we - // have already met the movement goal. - if (!goalMet) { - const buffered = []; - for (let i = 0; i < target.buffered.length; ++i) { - buffered.push({ - start: target.buffered.start(i), - end: target.buffered.end(i), - }); - } + shaka.test.Util.delay(timeout).then(() => { + // This check is only necessary to supress the error log. It's fine to + // unlisten twice or to reject after resolve. Neither of those actions + // matter. But the error log can be confusing during debugging if we + // have already met the movement goal. + if (!goalMet) { + const buffered = []; + for (let i = 0; i < target.buffered.length; ++i) { + buffered.push({ + start: target.buffered.start(i), + end: target.buffered.end(i), + }); + } - shaka.log.error('Timeout waiting for playback.', - 'current time', target.currentTime, - 'ready state', target.readyState, - 'playback rate', target.playbackRate, - 'paused', target.paused, - 'buffered', buffered); + shaka.log.error('Timeout waiting for playback.', + 'current time', target.currentTime, + 'ready state', target.readyState, + 'playback rate', target.playbackRate, + 'paused', target.paused, + 'buffered', buffered); - eventManager.unlisten(target, 'timeupdate'); - reject(new Error('Timeout while waiting for playback!')); - } - }); - }); -}; + eventManager.unlisten(target, 'timeupdate'); + reject(new Error('Timeout while waiting for playback!')); + } + }); + }); + }; /** * @param {shaka.util.EventManager} eventManager @@ -437,41 +437,41 @@ shaka.test.Util.waitForMovementOrFailOnTimeout = */ shaka.test.Util.waitUntilPlayheadReaches = (eventManager, target, playheadTime, timeout) => { - let goalMet = false; + let goalMet = false; - // TODO: Refactor all the wait utils into a class that avoids repeated args - return new Promise(((resolve, reject) => { - eventManager.listen(target, 'timeupdate', () => { - if (target.currentTime >= playheadTime) { - goalMet = true; - eventManager.unlisten(target, 'timeupdate'); - resolve(); - } - }); + // TODO: Refactor all the wait utils into a class that avoids repeated args + return new Promise(((resolve, reject) => { + eventManager.listen(target, 'timeupdate', () => { + if (target.currentTime >= playheadTime) { + goalMet = true; + eventManager.unlisten(target, 'timeupdate'); + resolve(); + } + }); - shaka.test.Util.delay(timeout).then(() => { - if (!goalMet) { - const buffered = []; - for (let i = 0; i < target.buffered.length; ++i) { - buffered.push({ - start: target.buffered.start(i), - end: target.buffered.end(i), - }); - } + shaka.test.Util.delay(timeout).then(() => { + if (!goalMet) { + const buffered = []; + for (let i = 0; i < target.buffered.length; ++i) { + buffered.push({ + start: target.buffered.start(i), + end: target.buffered.end(i), + }); + } - shaka.log.error('Timeout waiting for target time', playheadTime, - 'current time', target.currentTime, - 'ready state', target.readyState, - 'playback rate', target.playbackRate, - 'paused', target.paused, - 'buffered', buffered); + shaka.log.error('Timeout waiting for target time', playheadTime, + 'current time', target.currentTime, + 'ready state', target.readyState, + 'playback rate', target.playbackRate, + 'paused', target.paused, + 'buffered', buffered); - eventManager.unlisten(target, 'timeupdate'); - reject(new Error('Timeout waiting for time ' + playheadTime)); - } - }); - })); -}; + eventManager.unlisten(target, 'timeupdate'); + reject(new Error('Timeout waiting for time ' + playheadTime)); + } + }); + })); + }; /** * Wait for the video to end or for |timeout| seconds to pass, whichever diff --git a/test/text/text_engine_unit.js b/test/text/text_engine_unit.js index 91dfe206c..f272eca3c 100644 --- a/test/text/text_engine_unit.js +++ b/test/text/text_engine_unit.js @@ -69,18 +69,18 @@ describe('TextEngine', () => { }); it('reports support when it\'s closed captions and muxjs is available', - () => { - const closedCaptionsType = + () => { + const closedCaptionsType = shaka.util.MimeUtils.CLOSED_CAPTION_MIMETYPE; - const originalMuxjs = window.muxjs; - expect(TextEngine.isTypeSupported(closedCaptionsType)).toBe(true); - try { - window['muxjs'] = null; - expect(TextEngine.isTypeSupported(closedCaptionsType)).toBe(false); - } finally { - window['muxjs'] = originalMuxjs; - } - }); + const originalMuxjs = window.muxjs; + expect(TextEngine.isTypeSupported(closedCaptionsType)).toBe(true); + try { + window['muxjs'] = null; + expect(TextEngine.isTypeSupported(closedCaptionsType)).toBe(false); + } finally { + window['muxjs'] = originalMuxjs; + } + }); }); describe('appendBuffer', () => { @@ -99,8 +99,8 @@ describe('TextEngine', () => { await textEngine.appendBuffer(dummyData, 0, 3); expect(mockParseMedia).toHaveBeenCalledOnceMoreWith([ - new Uint8Array(dummyData), - {periodStart: 0, segmentStart: 0, segmentEnd: 3}, + new Uint8Array(dummyData), + {periodStart: 0, segmentStart: 0, segmentEnd: 3}, ]); expect(mockDisplayer.appendSpy).toHaveBeenCalledOnceMoreWith([ @@ -272,9 +272,9 @@ describe('TextEngine', () => { mockParseMedia.and.callFake((data, time) => { return [ createFakeCue(time.periodStart + 0, - time.periodStart + 1), + time.periodStart + 1), createFakeCue(time.periodStart + 2, - time.periodStart + 3), + time.periodStart + 3), ]; }); diff --git a/test/text/ttml_text_parser_unit.js b/test/text/ttml_text_parser_unit.js index 6a5d6fb55..6c8ead6eb 100644 --- a/test/text/ttml_text_parser_unit.js +++ b/test/text/ttml_text_parser_unit.js @@ -63,7 +63,7 @@ describe('TtmlTextParser', () => { {periodStart: 0, segmentStart: 0, segmentEnd: 0}); // Any other value is rejected as an error. errorHelper(shaka.util.Error.Code.INVALID_XML, - '<tt xml:space="invalid">' + ttBody + '</tt>'); + '<tt xml:space="invalid">' + ttBody + '</tt>'); }); it('rejects invalid ttml', () => { @@ -73,9 +73,9 @@ describe('TtmlTextParser', () => { it('rejects invalid time format', () => { errorHelper(shaka.util.Error.Code.INVALID_TEXT_CUE, - '<tt><body><p begin="test" end="test"></p></body></tt>'); + '<tt><body><p begin="test" end="test"></p></body></tt>'); errorHelper(shaka.util.Error.Code.INVALID_TEXT_CUE, - '<tt><body><p begin="3.45" end="1a"></p></body></tt>'); + '<tt><body><p begin="3.45" end="1a"></p></body></tt>'); }); it('supports colon formatted time', () => { @@ -286,17 +286,17 @@ describe('TtmlTextParser', () => { verifyHelper( [ { - start: 62.05, - end: 3723.2, - payload: 'Test', - region: { - id: 'subtitleArea', - viewportAnchorX: 50, - viewportAnchorY: 16, - width: 100, - height: 100, - }, - }, + start: 62.05, + end: 3723.2, + payload: 'Test', + region: { + id: 'subtitleArea', + viewportAnchorX: 50, + viewportAnchorY: 16, + width: 100, + height: 100, + }, + }, ], '<tt xmlns:tts="http://www.w3.org/ns/ttml#styling">' + '<layout>' + @@ -310,16 +310,16 @@ describe('TtmlTextParser', () => { verifyHelper( [ { - start: 62.05, - end: 3723.2, - payload: 'Test', - region: { - viewportAnchorX: 50, - viewportAnchorY: 16, - width: 100, - height: 100, - }, - }, + start: 62.05, + end: 3723.2, + payload: 'Test', + region: { + viewportAnchorX: 50, + viewportAnchorY: 16, + width: 100, + height: 100, + }, + }, ], '<tt xmlns:tts="http://www.w3.org/ns/ttml#styling">' + '<layout>' + @@ -334,16 +334,16 @@ describe('TtmlTextParser', () => { verifyHelper( [ { - start: 62.05, - end: 3723.2, - payload: 'Test', - region: { - viewportAnchorX: 50, - viewportAnchorY: 16, - width: 100, - height: 100, - }, - }, + start: 62.05, + end: 3723.2, + payload: 'Test', + region: { + viewportAnchorX: 50, + viewportAnchorY: 16, + width: 100, + height: 100, + }, + }, ], '<tt xmlns:tts="http://www.w3.org/ns/ttml#styling">' + '<layout>' + @@ -361,23 +361,23 @@ describe('TtmlTextParser', () => { verifyHelper( [ { - start: 62.05, - end: 3723.2, - payload: 'Test', - region: { - id: 'subtitleArea', - viewportAnchorX: 50, - viewportAnchorY: 16, - regionAnchorX: 0, - regionAnchorY: 0, - width: 100, - height: 100, - heightUnits: CueRegion.units.PERCENTAGE, - widthUnits: CueRegion.units.PERCENTAGE, - viewportAnchorUnits: CueRegion.units.PX, - scroll: CueRegion.scrollMode.NONE, - }, - }, + start: 62.05, + end: 3723.2, + payload: 'Test', + region: { + id: 'subtitleArea', + viewportAnchorX: 50, + viewportAnchorY: 16, + regionAnchorX: 0, + regionAnchorY: 0, + width: 100, + height: 100, + heightUnits: CueRegion.units.PERCENTAGE, + widthUnits: CueRegion.units.PERCENTAGE, + viewportAnchorUnits: CueRegion.units.PX, + scroll: CueRegion.scrollMode.NONE, + }, + }, ], '<tt xmlns:tts="http://www.w3.org/ns/ttml#styling">' + '<layout>' + @@ -391,23 +391,23 @@ describe('TtmlTextParser', () => { verifyHelper( [ { - start: 62.05, - end: 3723.2, - payload: 'Test', - region: { - id: 'subtitleArea', - viewportAnchorX: 0, - viewportAnchorY: 0, - regionAnchorX: 0, - regionAnchorY: 0, - width: 50, - height: 16, - heightUnits: CueRegion.units.PX, - widthUnits: CueRegion.units.PX, - viewportAnchorUnits: CueRegion.units.PERCENTAGE, - scroll: CueRegion.scrollMode.NONE, + start: 62.05, + end: 3723.2, + payload: 'Test', + region: { + id: 'subtitleArea', + viewportAnchorX: 0, + viewportAnchorY: 0, + regionAnchorX: 0, + regionAnchorY: 0, + width: 50, + height: 16, + heightUnits: CueRegion.units.PX, + widthUnits: CueRegion.units.PX, + viewportAnchorUnits: CueRegion.units.PERCENTAGE, + scroll: CueRegion.scrollMode.NONE, }, - }, + }, ], '<tt xmlns:tts="http://www.w3.org/ns/ttml#styling">' + '<layout>' + @@ -425,17 +425,17 @@ describe('TtmlTextParser', () => { verifyHelper( [ { - start: 62.05, - end: 3723.2, - payload: 'Test', - region: { - id: 'subtitleArea', - viewportAnchorX: 50, - viewportAnchorY: 16, - width: 100, - height: 100, - }, - }, + start: 62.05, + end: 3723.2, + payload: 'Test', + region: { + id: 'subtitleArea', + viewportAnchorX: 50, + viewportAnchorY: 16, + width: 100, + height: 100, + }, + }, ], '<tt xmlns:tts="http://www.w3.org/ns/ttml#styling">' + '<layout>' + @@ -450,16 +450,16 @@ describe('TtmlTextParser', () => { verifyHelper( [ { - start: 62.05, - end: 3723.2, - payload: 'Test', - region: { - viewportAnchorX: 50, - viewportAnchorY: 16, - width: 100, - height: 100, - }, - }, + start: 62.05, + end: 3723.2, + payload: 'Test', + region: { + viewportAnchorX: 50, + viewportAnchorY: 16, + width: 100, + height: 100, + }, + }, ], '<tt xmlns:tts="http://www.w3.org/ns/ttml#styling">' + '<layout>' + @@ -474,16 +474,16 @@ describe('TtmlTextParser', () => { verifyHelper( [ { - start: 62.05, - end: 3723.2, - payload: 'Test', - region: { - viewportAnchorX: 50, - viewportAnchorY: 16, - width: 100, - height: 100, - }, - }, + start: 62.05, + end: 3723.2, + payload: 'Test', + region: { + viewportAnchorX: 50, + viewportAnchorY: 16, + width: 100, + height: 100, + }, + }, ], '<tt xmlns:tts="http://www.w3.org/ns/ttml#styling">' + '<layout>' + @@ -746,7 +746,7 @@ describe('TtmlTextParser', () => { end: 3723.2, payload: 'Test', textDecoration: [Cue.textDecoration.UNDERLINE, - Cue.textDecoration.OVERLINE], + Cue.textDecoration.OVERLINE], }, ], '<tt xmlns:tts="http://www.w3.org/ns/ttml#styling">' + @@ -800,9 +800,9 @@ describe('TtmlTextParser', () => { const data = new Uint8Array(shaka.util.StringUtils.toUTF8(text)); const result = new shaka.text.TtmlTextParser().parseMedia(data, time); const properties = ['textAlign', 'lineAlign', 'positionAlign', 'size', - 'line', 'position', 'direction', 'color', 'writingMode', - 'backgroundColor', 'fontWeight', 'fontFamily', - 'wrapLine', 'lineHeight', 'fontStyle', 'fontSize']; + 'line', 'position', 'direction', 'color', 'writingMode', + 'backgroundColor', 'fontWeight', 'fontFamily', + 'wrapLine', 'lineHeight', 'fontStyle', 'fontSize']; expect(result).toBeTruthy(); expect(result.length).toBe(cues.length); for (let i = 0; i < cues.length; i++) { @@ -824,7 +824,7 @@ describe('TtmlTextParser', () => { if (cues[i].textDecoration) { for (let j = 0; j < cues[i].textDecoration.length; j++) { expect(/** @type {?} */ (result[i]).textDecoration[j]) - .toBe(cues[i].textDecoration[j]); + .toBe(cues[i].textDecoration[j]); } } } @@ -837,9 +837,9 @@ describe('TtmlTextParser', () => { */ function verifyRegion(expected, actual) { const properties = ['id', 'viewportAnchorX', 'viewportAnchorY', - 'regionAnchorX', 'regionAnchorY', 'width', 'height', - 'heightUnits', 'widthUnits', 'viewportAnchorUnits', - 'scroll']; + 'regionAnchorX', 'regionAnchorY', 'width', 'height', + 'heightUnits', 'widthUnits', 'viewportAnchorUnits', + 'scroll']; expect(actual).toBeTruthy(); for (let i = 0; i < properties.length; i++) { diff --git a/test/text/vtt_text_parser_unit.js b/test/text/vtt_text_parser_unit.js index 5bd6ff027..d1c84c834 100644 --- a/test/text/vtt_text_parser_unit.js +++ b/test/text/vtt_text_parser_unit.js @@ -174,38 +174,38 @@ describe('VttTextParser', () => { it('requires header', () => { errorHelper(shaka.util.Error.Code.INVALID_TEXT_HEADER, - '', - {periodStart: 0, segmentStart: 0, segmentEnd: 0}); + '', + {periodStart: 0, segmentStart: 0, segmentEnd: 0}); errorHelper(shaka.util.Error.Code.INVALID_TEXT_HEADER, - '00:00:00.000 --> 00:00:00.020\nTest', - {periodStart: 0, segmentStart: 0, segmentEnd: 0}); + '00:00:00.000 --> 00:00:00.020\nTest', + {periodStart: 0, segmentStart: 0, segmentEnd: 0}); }); it('rejects invalid time values', () => { errorHelper(shaka.util.Error.Code.INVALID_TEXT_CUE, - 'WEBVTT\n\n00.020 --> 0:00.040\nTest', - {periodStart: 0, segmentStart: 0, segmentEnd: 0}); + 'WEBVTT\n\n00.020 --> 0:00.040\nTest', + {periodStart: 0, segmentStart: 0, segmentEnd: 0}); errorHelper(shaka.util.Error.Code.INVALID_TEXT_CUE, - 'WEBVTT\n\n0:00.020 --> 0:00.040\nTest', - {periodStart: 0, segmentStart: 0, segmentEnd: 0}); + 'WEBVTT\n\n0:00.020 --> 0:00.040\nTest', + {periodStart: 0, segmentStart: 0, segmentEnd: 0}); errorHelper(shaka.util.Error.Code.INVALID_TEXT_CUE, - 'WEBVTT\n\n00:00.20 --> 0:00.040\nTest', - {periodStart: 0, segmentStart: 0, segmentEnd: 0}); + 'WEBVTT\n\n00:00.20 --> 0:00.040\nTest', + {periodStart: 0, segmentStart: 0, segmentEnd: 0}); errorHelper(shaka.util.Error.Code.INVALID_TEXT_CUE, - 'WEBVTT\n\n00:100.20 --> 0:00.040\nTest', - {periodStart: 0, segmentStart: 0, segmentEnd: 0}); + 'WEBVTT\n\n00:100.20 --> 0:00.040\nTest', + {periodStart: 0, segmentStart: 0, segmentEnd: 0}); errorHelper(shaka.util.Error.Code.INVALID_TEXT_CUE, - 'WEBVTT\n\n00:00.020 --> 0:00.040\nTest', - {periodStart: 0, segmentStart: 0, segmentEnd: 0}); + 'WEBVTT\n\n00:00.020 --> 0:00.040\nTest', + {periodStart: 0, segmentStart: 0, segmentEnd: 0}); errorHelper(shaka.util.Error.Code.INVALID_TEXT_CUE, - 'WEBVTT\n\n00:00:00:00.020 --> 0:00.040\nTest', - {periodStart: 0, segmentStart: 0, segmentEnd: 0}); + 'WEBVTT\n\n00:00:00:00.020 --> 0:00.040\nTest', + {periodStart: 0, segmentStart: 0, segmentEnd: 0}); errorHelper(shaka.util.Error.Code.INVALID_TEXT_CUE, - 'WEBVTT\n\n00:61.020 --> 0:00.040\nTest', - {periodStart: 0, segmentStart: 0, segmentEnd: 0}); + 'WEBVTT\n\n00:61.020 --> 0:00.040\nTest', + {periodStart: 0, segmentStart: 0, segmentEnd: 0}); errorHelper(shaka.util.Error.Code.INVALID_TEXT_CUE, - 'WEBVTT\n\n61:00.020 --> 0:00.040\nTest', - {periodStart: 0, segmentStart: 0, segmentEnd: 0}); + 'WEBVTT\n\n61:00.020 --> 0:00.040\nTest', + {periodStart: 0, segmentStart: 0, segmentEnd: 0}); }); it('supports vertical setting', () => { @@ -635,9 +635,9 @@ describe('VttTextParser', () => { */ function verifyRegion(expected, actual) { const properties = ['id', 'viewportAnchorX', 'viewportAnchorY', - 'regionAnchorX', 'regionAnchorY', 'width', 'height', - 'heightUnits', 'widthUnits', 'viewportAnchorUnits', - 'scroll']; + 'regionAnchorX', 'regionAnchorY', 'width', 'height', + 'heightUnits', 'widthUnits', 'viewportAnchorUnits', + 'scroll']; expect(actual).toBeTruthy(); for (let i = 0; i < properties.length; i++) { diff --git a/test/ui/ui_integration.js b/test/ui/ui_integration.js index 8fa74b761..e21c62044 100644 --- a/test/ui/ui_integration.js +++ b/test/ui/ui_integration.js @@ -169,9 +169,9 @@ describe('UI', () => { it('choosing caption language through UI has effect on player', async () => { - await verifyLanguageChangeViaUI( - 'textchanged', () => player.getTextTracks()); - }); + await verifyLanguageChangeViaUI( + 'textchanged', () => player.getTextTracks()); + }); it('choosing language through API has effect on UI', async () => { // Enable & verify the text, or else the text won't be streamed and the @@ -244,9 +244,9 @@ describe('UI', () => { ['shaka-back-to-overflow-button', 'shaka-turn-captions-off-button']); languagesToButtons = mapChoicesToButtons( - /* allButtons= */ languageButtons, - /* choices= */ langsFromContent, - /* modifier= */ getNativeName, + /* allButtons= */ languageButtons, + /* choices= */ langsFromContent, + /* modifier= */ getNativeName, ); } @@ -309,9 +309,9 @@ describe('UI', () => { ['shaka-back-to-overflow-button', 'shaka-turn-captions-off-button']); languagesToButtons = mapChoicesToButtons( - /* allButtons= */ languageButtons, - /* choices */ langsFromContent, - /* modifier */ getNativeName + /* allButtons= */ languageButtons, + /* choices */ langsFromContent, + /* modifier */ getNativeName ); const button = languagesToButtons.get(newLanguage); @@ -542,11 +542,11 @@ describe('UI', () => { }); resolutionButtons = filterButtons( - /* buttons= */ resolutionsMenu.childNodes, - /* excludeClasses= */ [ - 'shaka-back-to-overflow-button', - 'shaka-enable-abr-button', - ]); + /* buttons= */ resolutionsMenu.childNodes, + /* excludeClasses= */ [ + 'shaka-back-to-overflow-button', + 'shaka-enable-abr-button', + ]); resolutionsToButtons = mapChoicesToButtons( /* buttons= */ resolutionButtons, diff --git a/test/ui/ui_unit.js b/test/ui/ui_unit.js index 879b7edff..6ea0a6d38 100644 --- a/test/ui/ui_unit.js +++ b/test/ui/ui_unit.js @@ -43,7 +43,7 @@ describe('UI', () => { beforeEach(() => { videoContainer = - /** @type {!HTMLElement} */ (document.createElement('div')); + /** @type {!HTMLElement} */ (document.createElement('div')); document.body.appendChild(videoContainer); video = shaka.util.Dom.createVideoElement(); @@ -63,7 +63,7 @@ describe('UI', () => { beforeEach(() => { container = - /** @type {!HTMLElement} */ (document.createElement('div')); + /** @type {!HTMLElement} */ (document.createElement('div')); document.body.appendChild(container); createUIThroughDOMAutoSetup([container], /* videos */ []); @@ -83,11 +83,11 @@ describe('UI', () => { beforeEach(() => { container1 = - /** @type {!HTMLElement} */ (document.createElement('div')); + /** @type {!HTMLElement} */ (document.createElement('div')); document.body.appendChild(container1); container2 = - /** @type {!HTMLElement} */ (document.createElement('div')); + /** @type {!HTMLElement} */ (document.createElement('div')); document.body.appendChild(container2); createUIThroughDOMAutoSetup([container1, container2], /* videos */ []); @@ -151,7 +151,7 @@ describe('UI', () => { beforeEach(() => { container = - /** @type {!HTMLElement} */ (document.createElement('div')); + /** @type {!HTMLElement} */ (document.createElement('div')); document.body.appendChild(container); video = shaka.util.Dom.createVideoElement(); @@ -174,7 +174,7 @@ describe('UI', () => { beforeEach(() => { videoContainer = - /** @type {!HTMLElement} */ (document.createElement('div')); + /** @type {!HTMLElement} */ (document.createElement('div')); document.body.appendChild(videoContainer); video = shaka.util.Dom.createVideoElement(); @@ -182,7 +182,7 @@ describe('UI', () => { }); describe('all the controls', () => { - /** @type {!HTMLElement} */ + /** @type {!HTMLElement} */ let controlsContainer; beforeEach(() => { @@ -211,7 +211,7 @@ describe('UI', () => { }); describe('overflow menu', () => { - /** @type {!HTMLElement} */ + /** @type {!HTMLElement} */ let overflowMenu; beforeEach(() => { @@ -251,30 +251,30 @@ describe('UI', () => { it('allows picture-in-picture only when the content has video', async () => { - // Load fake content that contains only audio. - const manifest = new shaka.test.ManifestGenerator() - .addPeriod(/* startTime= */ 0) - .addVariant(/* id= */ 0) + // Load fake content that contains only audio. + const manifest = new shaka.test.ManifestGenerator() + .addPeriod(/* startTime= */ 0) + .addVariant(/* id= */ 0) .addAudio(/* id= */ 1) - .build(); + .build(); - const parser = new shaka.test.FakeManifestParser(manifest); - const factory = () => parser; + const parser = new shaka.test.FakeManifestParser(manifest); + const factory = () => parser; - await player.load(/* uri= */ 'fake', /* startTime= */ 0, factory); - const pipButtons = + await player.load(/* uri= */ 'fake', /* startTime= */ 0, factory); + const pipButtons = videoContainer.getElementsByClassName('shaka-pip-button'); - expect(pipButtons.length).toBe(1); - const pipButton = pipButtons[0]; + expect(pipButtons.length).toBe(1); + const pipButton = pipButtons[0]; - // The picture-in-picture button should not be shown when the content - // only has audio. - expect(pipButton.classList.contains('shaka-hidden')).toBe(true); + // The picture-in-picture button should not be shown when the content + // only has audio. + expect(pipButton.classList.contains('shaka-hidden')).toBe(true); - // The picture-in-picture window should not be open when the content - // only has audio. - expect(document.pictureInPictureElement).toBeFalsy(); - }); + // The picture-in-picture window should not be open when the content + // only has audio. + expect(document.pictureInPictureElement).toBeFalsy(); + }); it('is accessible', () => { for (const button of overflowMenu.childNodes) { @@ -286,17 +286,17 @@ describe('UI', () => { describe('controls-button-panel', () => { - /** @type {!HTMLElement} */ + /** @type {!HTMLElement} */ let controlsButtonPanel; it('has default elements', () => { createUIThroughAPI(videoContainer, video); const controlsButtonPanels = videoContainer.getElementsByClassName( - 'shaka-controls-button-panel'); + 'shaka-controls-button-panel'); expect(controlsButtonPanels.length).toBe(1); controlsButtonPanel = - /** @type {!HTMLElement} */ (controlsButtonPanels[0]); + /** @type {!HTMLElement} */ (controlsButtonPanels[0]); confirmElementFound(controlsButtonPanel, 'shaka-current-time'); confirmElementFound(controlsButtonPanel, 'shaka-mute-button'); @@ -326,11 +326,11 @@ describe('UI', () => { createUIThroughAPI(videoContainer, video, config); const controlsButtonPanels = videoContainer.getElementsByClassName( - 'shaka-controls-button-panel'); + 'shaka-controls-button-panel'); expect(controlsButtonPanels.length).toBe(1); controlsButtonPanel = - /** @type {!HTMLElement} */ (controlsButtonPanels[0]); + /** @type {!HTMLElement} */ (controlsButtonPanels[0]); confirmAriaLabel('shaka-mute-button'); confirmAriaLabel('shaka-volume-bar'); @@ -342,7 +342,7 @@ describe('UI', () => { }); describe('resolutions menu', () => { - /** @type {!HTMLElement} */ + /** @type {!HTMLElement} */ let resolutionsMenu; beforeEach(() => { @@ -433,7 +433,7 @@ describe('UI', () => { shaka.log.warning = shaka.test.Util.spyFunc(warning); warning.calls.reset(); container = - /** @type {!HTMLElement} */ (document.createElement('div')); + /** @type {!HTMLElement} */ (document.createElement('div')); document.body.appendChild(container); video = shaka.util.Dom.createVideoElement(); @@ -482,34 +482,34 @@ describe('UI', () => { it('settings menus are positioned lower when seek bar is absent', () => { - config = {addSeekBar: false}; - createUIThroughAPI(container, video, config); + config = {addSeekBar: false}; + createUIThroughAPI(container, video, config); - function confirmLowPosition(className) { - const elements = + function confirmLowPosition(className) { + const elements = container.getElementsByClassName(className); - expect(elements.length).toBe(1); - expect(elements[0].classList.contains('shaka-low-position')).toBe(true); - } + expect(elements.length).toBe(1); + expect(elements[0].classList.contains('shaka-low-position')).toBe(true); + } - confirmElementMissing(container, 'shaka-seek-bar'); + confirmElementMissing(container, 'shaka-seek-bar'); - confirmLowPosition('shaka-overflow-menu'); - confirmLowPosition('shaka-resolutions'); - confirmLowPosition('shaka-audio-languages'); - confirmLowPosition('shaka-text-languages'); - }); + confirmLowPosition('shaka-overflow-menu'); + confirmLowPosition('shaka-resolutions'); + confirmLowPosition('shaka-audio-languages'); + confirmLowPosition('shaka-text-languages'); + }); it('controls are created in specified order', () => { config = {controlPanelElements: ['mute', 'time_and_duration', - 'fullscreen']}; + 'fullscreen']}; createUIThroughAPI(container, video, config); const controlsButtonPanels = container.getElementsByClassName('shaka-controls-button-panel'); expect(controlsButtonPanels.length).toBe(1); const controlsButtonPanel = - /** @type {!HTMLElement} */ (controlsButtonPanels[0]); + /** @type {!HTMLElement} */ (controlsButtonPanels[0]); const buttons = controlsButtonPanel.childNodes; expect(buttons.length).toBe(3); diff --git a/test/util/ebml_parser_unit.js b/test/util/ebml_parser_unit.js index baefa2ec8..87c577210 100644 --- a/test/util/ebml_parser_unit.js +++ b/test/util/ebml_parser_unit.js @@ -44,7 +44,7 @@ describe('EbmlParser', /** @suppress {accessControls} */ () => { // Set size to 4 bytes. // Set the data to [0x09, 0x08, 0x07, 0x06]. const data = new Uint8Array([0x81, 0x84, 0x01, 0x02, 0x03, 0x04, 0x82, 0x84, - 0x09, 0x08, 0x07, 0x06]); + 0x09, 0x08, 0x07, 0x06]); const parser = new shaka.util.EbmlParser(new DataView(data.buffer)); const elem1 = parser.parseElement(); diff --git a/test/util/xml_utils_unit.js b/test/util/xml_utils_unit.js index 7cc15083d..798c5012a 100644 --- a/test/util/xml_utils_unit.js +++ b/test/util/xml_utils_unit.js @@ -148,7 +148,7 @@ describe('XmlUtils', () => { '</Root>', ].join('\n'); xml = /** @type {!Document} */ ( - new DOMParser().parseFromString(xmlString, 'application/xml')); + new DOMParser().parseFromString(xmlString, 'application/xml')); }); it('delegates to parser function', () => { diff --git a/ui/audio_language_selection.js b/ui/audio_language_selection.js index 091599803..5a698907d 100644 --- a/ui/audio_language_selection.js +++ b/ui/audio_language_selection.js @@ -45,14 +45,14 @@ shaka.ui.AudioLanguageSelection = class extends shaka.ui.Element { this.addAudioLangMenu_(); this.eventManager.listen( - this.localization, shaka.ui.Localization.LOCALE_UPDATED, () => { - this.updateLocalizedStrings_(); - }); + this.localization, shaka.ui.Localization.LOCALE_UPDATED, () => { + this.updateLocalizedStrings_(); + }); this.eventManager.listen( - this.localization, shaka.ui.Localization.LOCALE_CHANGED, () => { - this.updateLocalizedStrings_(); - }); + this.localization, shaka.ui.Localization.LOCALE_CHANGED, () => { + this.updateLocalizedStrings_(); + }); this.eventManager.listen(this.player, 'trackschanged', () => { @@ -152,10 +152,10 @@ shaka.ui.AudioLanguageSelection = class extends shaka.ui.Element { const languages = this.player.getAudioLanguages(); shaka.ui.LanguageUtils.updateLanguages(tracks, this.audioLangMenu_, - languages, - this.onAudioLanguageSelected_.bind(this), /* updateChosen */ true, - this.currentAudioLanguage_, - this.localization); + languages, + this.onAudioLanguageSelected_.bind(this), /* updateChosen */ true, + this.currentAudioLanguage_, + this.localization); shaka.ui.Utils.focusOnTheChosenItem(this.audioLangMenu_); // TODO: document this event @@ -209,4 +209,4 @@ shaka.ui.AudioLanguageSelection.Factory = class { }; shaka.ui.OverflowMenu.registerElement( - 'language', new shaka.ui.AudioLanguageSelection.Factory()); + 'language', new shaka.ui.AudioLanguageSelection.Factory()); diff --git a/ui/cast_button.js b/ui/cast_button.js index a9e5f4214..344de2f92 100644 --- a/ui/cast_button.js +++ b/ui/cast_button.js @@ -61,7 +61,7 @@ shaka.ui.CastButton = class extends shaka.ui.Element { this.castCurrentSelectionSpan_ = shaka.util.Dom.createHTMLElement('span'); this.castCurrentSelectionSpan_.classList.add( - 'shaka-current-selection-span'); + 'shaka-current-selection-span'); label.appendChild(this.castCurrentSelectionSpan_); this.castButton_.appendChild(label); this.parent.appendChild(this.castButton_); @@ -73,26 +73,26 @@ shaka.ui.CastButton = class extends shaka.ui.Element { this.onCastStatusChange_(); this.eventManager.listen( - this.localization, shaka.ui.Localization.LOCALE_UPDATED, () => { - this.updateLocalizedStrings_(); - }); + this.localization, shaka.ui.Localization.LOCALE_UPDATED, () => { + this.updateLocalizedStrings_(); + }); this.eventManager.listen( - this.localization, shaka.ui.Localization.LOCALE_CHANGED, () => { - this.updateLocalizedStrings_(); - }); + this.localization, shaka.ui.Localization.LOCALE_CHANGED, () => { + this.updateLocalizedStrings_(); + }); this.eventManager.listen(this.castButton_, 'click', () => { - this.onCastClick_(); - }); + this.onCastClick_(); + }); this.eventManager.listen(this.controls, 'caststatuschanged', () => { - this.onCastStatusChange_(); - }); + this.onCastStatusChange_(); + }); } - /** @private */ + /** @private */ async onCastClick_() { if (this.castProxy_.isCasting()) { this.castProxy_.suggestDisconnect(); @@ -182,4 +182,4 @@ shaka.ui.CastButton.Factory = class { }; shaka.ui.OverflowMenu.registerElement( - 'cast', new shaka.ui.CastButton.Factory()); + 'cast', new shaka.ui.CastButton.Factory()); diff --git a/ui/controls.js b/ui/controls.js index e72e718b8..a7520b15e 100644 --- a/ui/controls.js +++ b/ui/controls.js @@ -59,7 +59,7 @@ shaka.ui.Controls = function(player, videoContainer, video, config) { /** @private {!shaka.cast.CastProxy} */ this.castProxy_ = new shaka.cast.CastProxy( - video, player, this.config_.castReceiverAppId); + video, player, this.config_.castReceiverAppId); /** @private {boolean} */ this.castAllowed_ = true; @@ -245,7 +245,7 @@ shaka.ui.Controls.prototype.destroy = async function() { */ - /** +/** * @event shaka.Controls.ResolutionSelectionUpdatedEvent * @description Fired when the resolution menu has finished updating. * @property {string} type @@ -287,7 +287,7 @@ shaka.ui.Controls.prototype.destroy = async function() { */ - /** +/** * @event shaka.Controls.UIUpdatedEvent * @description Fired after a call to ui.configure() once the UI has finished * updating. @@ -343,7 +343,7 @@ shaka.ui.Controls.prototype.setEnabledShakaControls = function(enabled) { this.enabled_ = enabled; if (enabled) { shaka.ui.Utils.setDisplay( - this.controlsButtonPanel_.parentElement, true); + this.controlsButtonPanel_.parentElement, true); // If we're hiding native controls, make sure the video element itself is // not tab-navigable. Our custom controls will still be tab-navigable. @@ -351,7 +351,7 @@ shaka.ui.Controls.prototype.setEnabledShakaControls = function(enabled) { this.video_.controls = false; } else { shaka.ui.Utils.setDisplay( - this.controlsButtonPanel_.parentElement, false); + this.controlsButtonPanel_.parentElement, false); } // The effects of play state changes are inhibited while showing native @@ -534,7 +534,7 @@ shaka.ui.Controls.prototype.updateLocalizedStrings_ = function() { if (this.seekBar_) { this.seekBar_.setAttribute(shaka.ui.Constants.ARIA_LABEL, - this.localization_.resolve(LocIds.SEEK)); + this.localization_.resolve(LocIds.SEEK)); } // Localize state-dependant labels @@ -583,7 +583,7 @@ shaka.ui.Controls.prototype.createDOM_ = function() { /** @private {!Array.<!Element>} */ this.settingsMenus_ = Array.from( - this.videoContainer_.getElementsByClassName('shaka-settings-menu')); + this.videoContainer_.getElementsByClassName('shaka-settings-menu')); // Settings menus need to be positioned lower, if the seekbar is absent. if (!this.seekBar_) { @@ -627,14 +627,14 @@ shaka.ui.Controls.prototype.addPlayButton_ = function() { */ shaka.ui.Controls.prototype.addBufferingSpinner_ = function() { goog.asserts.assert(this.playButtonContainer_, - 'Must have play button container before spinner!'); + 'Must have play button container before spinner!'); // Svg elements have to be created with the svg xml namespace. const xmlns = 'http://www.w3.org/2000/svg'; /** @private {!HTMLElement} */ this.bufferingSpinner_ = - /** @type {!HTMLElement} */(document.createElementNS(xmlns, 'svg')); + /** @type {!HTMLElement} */(document.createElementNS(xmlns, 'svg')); // NOTE: SVG elements do not have a classList on IE, so use setAttribute. this.bufferingSpinner_.setAttribute('class', 'shaka-spinner-svg'); this.bufferingSpinner_.setAttribute('viewBox', '0 0 30 30'); @@ -675,7 +675,7 @@ shaka.ui.Controls.prototype.addControlsButtonPanel_ = function() { this.elements_.push(factory.create(this.controlsButtonPanel_, this)); } else { shaka.log.alwaysWarn('Unrecognized control panel element requested:', - name); + name); } } }; @@ -731,7 +731,7 @@ shaka.ui.Controls.prototype.addEventListeners_ = function() { for (let i = 0; i < noPropagationElements.length; i++) { const element = noPropagationElements[i]; element.addEventListener( - 'click', (event) => { event.stopPropagation(); }); + 'click', (event) => { event.stopPropagation(); }); } // Keep showing controls if one of those elements is hovered @@ -740,14 +740,14 @@ shaka.ui.Controls.prototype.addEventListeners_ = function() { for (let i = 0; i < showControlsElements.length; i++) { const element = showControlsElements[i]; element.addEventListener( - 'mouseover', () => { - this.overrideCssShowControls_ = true; - }); + 'mouseover', () => { + this.overrideCssShowControls_ = true; + }); element.addEventListener( - 'mouseleave', () => { - this.overrideCssShowControls_ = false; - }); + 'mouseleave', () => { + this.overrideCssShowControls_ = false; + }); } this.videoContainer_.addEventListener( @@ -990,11 +990,11 @@ shaka.ui.Controls.prototype.onPlayStateChange_ = function() { if (this.enabled_ && this.video_.paused && !this.isSeeking_) { this.playButton_.setAttribute('icon', 'play'); this.playButton_.setAttribute(shaka.ui.Constants.ARIA_LABEL, - this.localization_.resolve(shaka.ui.Locales.Ids.PLAY)); + this.localization_.resolve(shaka.ui.Locales.Ids.PLAY)); } else { this.playButton_.setAttribute('icon', 'pause'); this.playButton_.setAttribute(shaka.ui.Constants.ARIA_LABEL, - this.localization_.resolve(shaka.ui.Locales.Ids.PAUSE)); + this.localization_.resolve(shaka.ui.Locales.Ids.PAUSE)); } }; @@ -1102,7 +1102,7 @@ shaka.ui.Controls.prototype.onKeyUp_ = function(event) { this.onPlayPauseClick_(); } break; - } + } }; @@ -1165,7 +1165,7 @@ shaka.ui.Controls.prototype.updateTimeAndSeekRange_ = function() { return; } - const Constants = shaka.ui.Constants; + const Constants = shaka.ui.Constants; let displayTime = this.isSeeking_ ? Number(this.seekBar_.value) : Number(this.video_.currentTime); @@ -1269,7 +1269,7 @@ shaka.ui.Controls.prototype.onKeyDown_ = function(event) { // navigation. this.controlsContainer_.classList.add('shaka-keyboard-navigation'); this.eventManager_.listen(window, 'mousedown', - this.onMouseDown_.bind(this)); + this.onMouseDown_.bind(this)); } // If escape key was pressed, close any open settings menus. @@ -1279,10 +1279,10 @@ shaka.ui.Controls.prototype.onKeyDown_ = function(event) { if (anySettingsMenusAreOpen && this.pressedKeys_.has(shaka.ui.Constants.KEYCODE_TAB)) { - // If Tab key or Shift+Tab keys are pressed when navigating through - // an overflow settings menu, keep the focus to loop inside the - // overflow menu. - this.keepFocusInMenu_(event); + // If Tab key or Shift+Tab keys are pressed when navigating through + // an overflow settings menu, keep the focus to loop inside the + // overflow menu. + this.keepFocusInMenu_(event); } }; diff --git a/ui/enums.js b/ui/enums.js index 0b0ec56b8..b93d49b73 100644 --- a/ui/enums.js +++ b/ui/enums.js @@ -16,10 +16,10 @@ */ - goog.provide('shaka.ui.Enums'); +goog.provide('shaka.ui.Enums'); - /** +/** * These strings are used to insert material design icons * and should never be localized. * @enum {string} diff --git a/ui/fast_forward_button.js b/ui/fast_forward_button.js index bd7cefd31..afd93ca9c 100644 --- a/ui/fast_forward_button.js +++ b/ui/fast_forward_button.js @@ -46,14 +46,14 @@ shaka.ui.FastForwardButton = class extends shaka.ui.Element { this.updateAriaLabel_(); this.eventManager.listen( - this.localization, shaka.ui.Localization.LOCALE_UPDATED, () => { - this.updateAriaLabel_(); - }); + this.localization, shaka.ui.Localization.LOCALE_UPDATED, () => { + this.updateAriaLabel_(); + }); this.eventManager.listen( - this.localization, shaka.ui.Localization.LOCALE_CHANGED, () => { - this.updateAriaLabel_(); - }); + this.localization, shaka.ui.Localization.LOCALE_CHANGED, () => { + this.updateAriaLabel_(); + }); this.eventManager.listen(this.button_, 'click', () => { this.fastForward_(); @@ -99,4 +99,4 @@ shaka.ui.FastForwardButton.Factory = class { }; shaka.ui.Controls.registerElement( - 'fast_forward', new shaka.ui.FastForwardButton.Factory()); + 'fast_forward', new shaka.ui.FastForwardButton.Factory()); diff --git a/ui/fullscreen_button.js b/ui/fullscreen_button.js index 6c3fb9dea..1593276a0 100644 --- a/ui/fullscreen_button.js +++ b/ui/fullscreen_button.js @@ -55,18 +55,18 @@ shaka.ui.FullscreenButton = class extends shaka.ui.Element { this.videoContainer_ = this.controls.getVideoContainer(); this.eventManager.listen( - this.localization, shaka.ui.Localization.LOCALE_UPDATED, () => { - this.updateAriaLabel_(); - }); + this.localization, shaka.ui.Localization.LOCALE_UPDATED, () => { + this.updateAriaLabel_(); + }); this.eventManager.listen( - this.localization, shaka.ui.Localization.LOCALE_CHANGED, () => { - this.updateAriaLabel_(); - }); + this.localization, shaka.ui.Localization.LOCALE_CHANGED, () => { + this.updateAriaLabel_(); + }); this.eventManager.listen(this.button_, 'click', () => { - this.toggleFullScreen_(); - }); + this.toggleFullScreen_(); + }); if (screen.orientation) { this.eventManager.listen(screen.orientation, 'change', () => { @@ -75,9 +75,9 @@ shaka.ui.FullscreenButton = class extends shaka.ui.Element { } this.eventManager.listen(document, 'fullscreenchange', () => { - this.updateIcon_(); - this.updateAriaLabel_(); - }); + this.updateIcon_(); + this.updateAriaLabel_(); + }); } /** @@ -157,5 +157,5 @@ shaka.ui.FullscreenButton.Factory = class { }; shaka.ui.Controls.registerElement( - 'fullscreen', new shaka.ui.FullscreenButton.Factory()); + 'fullscreen', new shaka.ui.FullscreenButton.Factory()); diff --git a/ui/language_utils.js b/ui/language_utils.js index 375dbb342..7cc099ab7 100644 --- a/ui/language_utils.js +++ b/ui/language_utils.js @@ -32,8 +32,8 @@ shaka.ui.LanguageUtils = class { * @param {!HTMLElement} currentSelectionElement * @param {shaka.ui.Localization} localization */ - // TODO: Do the benefits of having this common code in a method still - // outweigh the complexity of the parameter list? + // TODO: Do the benefits of having this common code in a method still + // outweigh the complexity of the parameter list? static updateLanguages(tracks, langMenu, languages, onLanguageSelected, updateChosen, currentSelectionElement, localization) { // Using array.filter(f)[0] as an alternative to array.find(f) which is @@ -46,7 +46,7 @@ shaka.ui.LanguageUtils = class { // Remove old languages // 1. Save the back to menu button const backButton = shaka.ui.Utils.getFirstDescendantWithClassName( - langMenu, 'shaka-back-to-overflow-button'); + langMenu, 'shaka-back-to-overflow-button'); // 2. Remove everything shaka.ui.Utils.removeAllChildren(langMenu); diff --git a/ui/mute_button.js b/ui/mute_button.js index d5cb33b2c..3e4ec1e65 100644 --- a/ui/mute_button.js +++ b/ui/mute_button.js @@ -47,14 +47,14 @@ shaka.ui.MuteButton = class extends shaka.ui.Element { this.updateAriaLabel_(); this.eventManager.listen( - this.localization, shaka.ui.Localization.LOCALE_UPDATED, () => { - this.updateAriaLabel_(); - }); + this.localization, shaka.ui.Localization.LOCALE_UPDATED, () => { + this.updateAriaLabel_(); + }); this.eventManager.listen( - this.localization, shaka.ui.Localization.LOCALE_CHANGED, () => { - this.updateAriaLabel_(); - }); + this.localization, shaka.ui.Localization.LOCALE_CHANGED, () => { + this.updateAriaLabel_(); + }); this.eventManager.listen(this.button_, 'click', () => { this.video.muted = !this.video.muted; diff --git a/ui/overflow_menu.js b/ui/overflow_menu.js index 8804d4d43..ff24ac6c7 100644 --- a/ui/overflow_menu.js +++ b/ui/overflow_menu.js @@ -35,7 +35,7 @@ goog.require('shaka.util.Dom'); * @final * @export */ - shaka.ui.OverflowMenu = class extends shaka.ui.Element { +shaka.ui.OverflowMenu = class extends shaka.ui.Element { /** * @param {!HTMLElement} parent * @param {!shaka.ui.Controls} controls @@ -74,7 +74,7 @@ goog.require('shaka.util.Dom'); // overflow menu buttons, but oh well if (this.overflowMenu_.childNodes.length) { /** @type {!HTMLElement} */ (this.overflowMenu_.childNodes[0]) - .focus(); + .focus(); } // Make sure controls are displayed @@ -83,43 +83,43 @@ goog.require('shaka.util.Dom'); } this.eventManager.listen( - this.localization, shaka.ui.Localization.LOCALE_UPDATED, () => { - this.updateAriaLabel_(); - }); + this.localization, shaka.ui.Localization.LOCALE_UPDATED, () => { + this.updateAriaLabel_(); + }); this.eventManager.listen( - this.localization, shaka.ui.Localization.LOCALE_CHANGED, () => { - this.updateAriaLabel_(); - }); + this.localization, shaka.ui.Localization.LOCALE_CHANGED, () => { + this.updateAriaLabel_(); + }); this.eventManager.listen( - this.controls, 'submenuopen', () => { + this.controls, 'submenuopen', () => { // Hide the main overflow menu if one of the sub menus has // been opened. - shaka.ui.Utils.setDisplay(this.overflowMenu_, false); - }); + shaka.ui.Utils.setDisplay(this.overflowMenu_, false); + }); this.eventManager.listen( - this.overflowMenu_, 'touchstart', (event) => { - this.controls.setLastTouchEventTime(Date.now()); - event.stopPropagation(); - }); + this.overflowMenu_, 'touchstart', (event) => { + this.controls.setLastTouchEventTime(Date.now()); + event.stopPropagation(); + }); this.eventManager.listen(this.overflowMenuButton_, 'click', () => { - this.onOverflowMenuButtonClick_(); - }); + this.onOverflowMenuButtonClick_(); + }); this.eventManager.listen( - this.controlsContainer_, 'touchstart', (event) => { + this.controlsContainer_, 'touchstart', (event) => { // If the overflow menu is showing, hide it on a touch event - if (this.overflowMenu_.classList.contains('shaka-displayed')) { - shaka.ui.Utils.setDisplay(this.overflowMenu_, false); - // Stop this event from becoming a click event. - event.preventDefault(); - } - }); + if (this.overflowMenu_.classList.contains('shaka-displayed')) { + shaka.ui.Utils.setDisplay(this.overflowMenu_, false); + // Stop this event from becoming a click event. + event.preventDefault(); + } + }); this.updateAriaLabel_(); } @@ -186,7 +186,7 @@ goog.require('shaka.util.Dom'); this.children_.push(factory.create(this.overflowMenu_, this.controls)); } else { shaka.log.alwaysWarn('Unrecognized overflow menu element requested:', - name); + name); } } } @@ -239,7 +239,7 @@ shaka.ui.OverflowMenu.Factory = class { }; shaka.ui.Controls.registerElement( - 'overflow_menu', new shaka.ui.OverflowMenu.Factory()); + 'overflow_menu', new shaka.ui.OverflowMenu.Factory()); /** @private {!Map.<string, !shaka.extern.IUIElement.Factory>} */ diff --git a/ui/pip_button.js b/ui/pip_button.js index f17a57665..f51519853 100644 --- a/ui/pip_button.js +++ b/ui/pip_button.js @@ -79,14 +79,14 @@ shaka.ui.PipButton = class extends shaka.ui.Element { } this.eventManager.listen( - this.localization, shaka.ui.Localization.LOCALE_UPDATED, () => { - this.updateLocalizedStrings_(); - }); + this.localization, shaka.ui.Localization.LOCALE_UPDATED, () => { + this.updateLocalizedStrings_(); + }); this.eventManager.listen( - this.localization, shaka.ui.Localization.LOCALE_CHANGED, () => { - this.updateLocalizedStrings_(); - }); + this.localization, shaka.ui.Localization.LOCALE_CHANGED, () => { + this.updateLocalizedStrings_(); + }); this.eventManager.listen(this.pipButton_, 'click', () => { this.onPipClick_(); @@ -241,4 +241,4 @@ shaka.ui.PipButton.Factory = class { }; shaka.ui.OverflowMenu.registerElement( - 'picture_in_picture', new shaka.ui.PipButton.Factory()); + 'picture_in_picture', new shaka.ui.PipButton.Factory()); diff --git a/ui/presentation_time.js b/ui/presentation_time.js index 6d124cab9..bd7c71d05 100644 --- a/ui/presentation_time.js +++ b/ui/presentation_time.js @@ -153,4 +153,4 @@ shaka.ui.PresentationTimeTracker.Factory = class { }; shaka.ui.Controls.registerElement( - 'time_and_duration', new shaka.ui.PresentationTimeTracker.Factory()); + 'time_and_duration', new shaka.ui.PresentationTimeTracker.Factory()); diff --git a/ui/resolution_selection.js b/ui/resolution_selection.js index ed89a9d6f..110a2b33e 100644 --- a/ui/resolution_selection.js +++ b/ui/resolution_selection.js @@ -44,30 +44,30 @@ shaka.ui.ResolutionSelection = class extends shaka.ui.Element { this.addResolutionMenu_(); this.eventManager.listen( - this.localization, shaka.ui.Localization.LOCALE_UPDATED, () => { - this.updateLocalizedStrings_(); - }); + this.localization, shaka.ui.Localization.LOCALE_UPDATED, () => { + this.updateLocalizedStrings_(); + }); this.eventManager.listen( - this.localization, shaka.ui.Localization.LOCALE_CHANGED, () => { - this.updateLocalizedStrings_(); - }); + this.localization, shaka.ui.Localization.LOCALE_CHANGED, () => { + this.updateLocalizedStrings_(); + }); this.eventManager.listen(this.resolutionButton_, 'click', () => { - this.onResolutionClick_(); - }); + this.onResolutionClick_(); + }); this.eventManager.listen(this.player, 'variantchanged', () => { - this.updateResolutionSelection_(); - }); + this.updateResolutionSelection_(); + }); this.eventManager.listen(this.player, 'trackschanged', () => { - this.updateResolutionSelection_(); - }); + this.updateResolutionSelection_(); + }); this.eventManager.listen(this.player, 'abrstatuschanged', () => { - this.updateResolutionSelection_(); - }); + this.updateResolutionSelection_(); + }); this.updateResolutionSelection_(); @@ -110,7 +110,7 @@ shaka.ui.ResolutionSelection = class extends shaka.ui.Element { /** * @private */ - addResolutionMenu_() { + addResolutionMenu_() { /** @private {!HTMLElement}*/ this.resolutionMenu_ = shaka.util.Dom.createHTMLElement('div'); this.resolutionMenu_.classList.add('shaka-resolutions'); @@ -122,7 +122,7 @@ shaka.ui.ResolutionSelection = class extends shaka.ui.Element { this.backFromResolutionButton_ = shaka.util.Dom.createHTMLElement('button'); this.backFromResolutionButton_.classList.add( - 'shaka-back-to-overflow-button'); + 'shaka-back-to-overflow-button'); this.resolutionMenu_.appendChild(this.backFromResolutionButton_); const backIcon = shaka.util.Dom.createHTMLElement('i'); @@ -293,4 +293,4 @@ shaka.ui.ResolutionSelection.Factory = class { }; shaka.ui.OverflowMenu.registerElement( - 'quality', new shaka.ui.ResolutionSelection.Factory()); + 'quality', new shaka.ui.ResolutionSelection.Factory()); diff --git a/ui/rewind_button.js b/ui/rewind_button.js index fbec666f5..47045071e 100644 --- a/ui/rewind_button.js +++ b/ui/rewind_button.js @@ -48,14 +48,14 @@ shaka.ui.RewindButton = class extends shaka.ui.Element { this.updateAriaLabel_(); this.eventManager.listen( - this.localization, shaka.ui.Localization.LOCALE_UPDATED, () => { - this.updateAriaLabel_(); - }); + this.localization, shaka.ui.Localization.LOCALE_UPDATED, () => { + this.updateAriaLabel_(); + }); this.eventManager.listen( - this.localization, shaka.ui.Localization.LOCALE_CHANGED, () => { - this.updateAriaLabel_(); - }); + this.localization, shaka.ui.Localization.LOCALE_CHANGED, () => { + this.updateAriaLabel_(); + }); this.eventManager.listen(this.button_, 'click', () => { this.rewind_(); @@ -102,5 +102,5 @@ shaka.ui.RewindButton.Factory = class { }; shaka.ui.Controls.registerElement( - 'rewind', new shaka.ui.RewindButton.Factory()); + 'rewind', new shaka.ui.RewindButton.Factory()); diff --git a/ui/spacer.js b/ui/spacer.js index f72fe06dc..be743f083 100644 --- a/ui/spacer.js +++ b/ui/spacer.js @@ -56,4 +56,4 @@ shaka.ui.Spacer.Factory = class { }; shaka.ui.Controls.registerElement( - 'spacer', new shaka.ui.Spacer.Factory()); + 'spacer', new shaka.ui.Spacer.Factory()); diff --git a/ui/text_displayer.js b/ui/text_displayer.js index 930d28a4c..e6b7ba937 100644 --- a/ui/text_displayer.js +++ b/ui/text_displayer.js @@ -115,11 +115,11 @@ shaka.ui.TextDisplayer = class { } for (const cue of cuesToRemove) { - const captions = this.currentCuesMap_.get(cue); - if (captions) { - this.textContainer_.removeChild(captions); - this.currentCuesMap_.delete(cue); - } + const captions = this.currentCuesMap_.get(cue); + if (captions) { + this.textContainer_.removeChild(captions); + this.currentCuesMap_.delete(cue); + } } // Remove the cues out of the time range. @@ -160,7 +160,7 @@ shaka.ui.TextDisplayer = class { // For each cue in the current cues map, if the cue's end time has passed, // remove the entry from the map, and remove the captions from the page. for (const cue of this.currentCuesMap_.keys()) { - if (!shouldCueBeDisplayed(cue)) { + if (!shouldCueBeDisplayed(cue)) { const captions = this.currentCuesMap_.get(cue); this.textContainer_.removeChild(captions); this.currentCuesMap_.delete(cue); diff --git a/ui/text_selection.js b/ui/text_selection.js index 01662214d..62e73bc5a 100644 --- a/ui/text_selection.js +++ b/ui/text_selection.js @@ -45,22 +45,22 @@ shaka.ui.TextSelection = class extends shaka.ui.Element { this.addTextLangMenu_(); this.eventManager.listen( - this.localization, shaka.ui.Localization.LOCALE_UPDATED, () => { - this.updateLocalizedStrings_(); - // If captions/subtitles are off, this string needs localization. - // TODO: is there a more efficient way of updating just the strings - // we need instead of running the whole language update? - this.updateTextLanguages_(); - }); + this.localization, shaka.ui.Localization.LOCALE_UPDATED, () => { + this.updateLocalizedStrings_(); + // If captions/subtitles are off, this string needs localization. + // TODO: is there a more efficient way of updating just the strings + // we need instead of running the whole language update? + this.updateTextLanguages_(); + }); this.eventManager.listen( - this.localization, shaka.ui.Localization.LOCALE_CHANGED, () => { - this.updateLocalizedStrings_(); - // If captions/subtitles are off, this string needs localization. - // TODO: is there a more efficient way of updating just the strings - // we need instead of running the whole language update? - this.updateTextLanguages_(); - }); + this.localization, shaka.ui.Localization.LOCALE_CHANGED, () => { + this.updateLocalizedStrings_(); + // If captions/subtitles are off, this string needs localization. + // TODO: is there a more efficient way of updating just the strings + // we need instead of running the whole language update? + this.updateTextLanguages_(); + }); this.eventManager.listen(this.player, 'texttrackvisibility', () => { this.onCaptionStateChange_(); @@ -205,12 +205,12 @@ shaka.ui.TextSelection = class extends shaka.ui.Element { }); shaka.ui.LanguageUtils.updateLanguages(tracks, this.textLangMenu_, - languages, - this.onTextLanguageSelected_.bind(this), - // Don't mark current text language as chosen unless captions are enabled - this.player.isTextTrackVisible(), - this.currentCaptions_, - this.localization); + languages, + this.onTextLanguageSelected_.bind(this), + // Don't mark current text language as chosen unless captions are enabled + this.player.isTextTrackVisible(), + this.currentCaptions_, + this.localization); // Add the Off button const offButton = shaka.util.Dom.createHTMLElement('button'); diff --git a/ui/ui.js b/ui/ui.js index e36dbd8b6..4a3030018 100644 --- a/ui/ui.js +++ b/ui/ui.js @@ -110,7 +110,7 @@ shaka.ui.Overlay.prototype.getConfiguration = function() { */ shaka.ui.Overlay.prototype.configure = function(config, value) { goog.asserts.assert(typeof(config) == 'object' || arguments.length == 2, - 'String configs should have values!'); + 'String configs should have values!'); // ('fieldName', value) format if (arguments.length == 2 && typeof(config) == 'string') { @@ -142,8 +142,8 @@ shaka.ui.Overlay.prototype.configure = function(config, value) { this.videoContainer_.appendChild(this.video_); shaka.util.ConfigUtils.mergeConfigObjects( - this.config_, config, this.defaultConfig_(), - /* overrides (only used for player config)*/ {}, /* path */ ''); + this.config_, config, this.defaultConfig_(), + /* overrides (only used for player config)*/ {}, /* path */ ''); // If a cast receiver app id has been given, add a cast button to the UI if (this.config_.castReceiverAppId && @@ -263,7 +263,7 @@ shaka.ui.Overlay.scanPageForShakaElements_ = function() { for (let i = 0; i < videos.length; i++) { const video = videos[i]; goog.asserts.assert(video.tagName.toLowerCase() == 'video', - 'Should be a video element!'); + 'Should be a video element!'); const container = document.createElement('div'); const videoParent = video.parentElement; @@ -292,7 +292,7 @@ shaka.ui.Overlay.scanPageForShakaElements_ = function() { for (let i = 0; i < containers.length; i++) { const container = containers[i]; goog.asserts.assert(container.tagName.toLowerCase() == 'div', - 'Container should be a div!'); + 'Container should be a div!'); let castAppId = ''; @@ -307,7 +307,7 @@ shaka.ui.Overlay.scanPageForShakaElements_ = function() { let video = null; for (let j = 0; j < videos.length; j++) { goog.asserts.assert(videos[j].tagName.toLowerCase() == 'video', - 'Should be a video element!'); + 'Should be a video element!'); if (videos[j].parentElement == container) { video = videos[j]; break; @@ -345,7 +345,7 @@ shaka.ui.Overlay.scanPageForShakaElements_ = function() { shaka.ui.Overlay.dispatchLoadedEvent_ = function(eventName) { // "Event" is not constructable on IE, so we use this CustomEvent pattern. const uiLoadedEvent = /** @type {!CustomEvent} */( - document.createEvent('CustomEvent')); + document.createEvent('CustomEvent')); uiLoadedEvent.initCustomEvent(eventName, false, false, null); document.dispatchEvent(uiLoadedEvent); diff --git a/ui/ui_utils.js b/ui/ui_utils.js index 223fd28a1..a063e890d 100644 --- a/ui/ui_utils.js +++ b/ui/ui_utils.js @@ -27,7 +27,7 @@ goog.require('goog.asserts'); * @return {!HTMLElement} * @export */ - // TODO: This can be replaced by shaka.util.Dom.getElementByClassName +// TODO: This can be replaced by shaka.util.Dom.getElementByClassName shaka.ui.Utils.getFirstDescendantWithClassName = function(element, className) { const descendant = shaka.ui.Utils.getDescendantIfExists(element, className); goog.asserts.assert(descendant != null, 'Should not be null!'); @@ -62,7 +62,7 @@ shaka.ui.Utils.focusOnTheChosenItem = function(menu) { return; } const chosenItem = shaka.ui.Utils.getDescendantIfExists( - menu, 'shaka-chosen-item'); + menu, 'shaka-chosen-item'); if (chosenItem) { chosenItem.parentElement.focus(); } @@ -100,7 +100,7 @@ shaka.ui.Utils.setDisplay = function(element, display) { // elements on that browser. It's better to find out on Chrome through an // assertion, rather than wait for a failed test pass later on IE. goog.asserts.assert(!(element instanceof SVGElement), - 'Do not use setDisplay with SVG elements!'); + 'Do not use setDisplay with SVG elements!'); if (display) { element.classList.add('shaka-displayed'); diff --git a/ui/volume_bar.js b/ui/volume_bar.js index 1acfa9bd9..14130d190 100644 --- a/ui/volume_bar.js +++ b/ui/volume_bar.js @@ -66,14 +66,14 @@ shaka.ui.VolumeBar = class extends shaka.ui.Element { }); this.eventManager.listen( - this.localization, shaka.ui.Localization.LOCALE_UPDATED, () => { - this.updateAriaLabel_(); - }); + this.localization, shaka.ui.Localization.LOCALE_UPDATED, () => { + this.updateAriaLabel_(); + }); this.eventManager.listen( - this.localization, shaka.ui.Localization.LOCALE_CHANGED, () => { - this.updateAriaLabel_(); - }); + this.localization, shaka.ui.Localization.LOCALE_CHANGED, () => { + this.updateAriaLabel_(); + }); // Initialize volume display with a fake event. this.onVolumeStateChange_(); @@ -85,9 +85,9 @@ shaka.ui.VolumeBar = class extends shaka.ui.Element { */ onVolumeStateChange_() { if (this.video.muted) { - this.bar_.value = 0; + this.bar_.value = 0; } else { - this.bar_.value = this.video.volume; + this.bar_.value = this.video.volume; } // TODO: Can we do this with LESS?