From 335eab08ba5eb4970e1ff51f1f211dce25321fe6 Mon Sep 17 00:00:00 2001 From: Dave Nicholas Date: Fri, 26 Jan 2024 12:01:51 +0000 Subject: [PATCH 01/64] feat(WebVTT): Handle badly formed VTT (#6147) Handle remove chevrons that appear as part of the inner text of the element to avoid parse failure. --- lib/text/vtt_text_parser.js | 27 +++++++++++++++++++++++++++ test/text/vtt_text_parser_unit.js | 28 +++++++++++++++++++++++++--- 2 files changed, 52 insertions(+), 3 deletions(-) diff --git a/lib/text/vtt_text_parser.js b/lib/text/vtt_text_parser.js index 4cb5387b1a..eeff9e496a 100644 --- a/lib/text/vtt_text_parser.js +++ b/lib/text/vtt_text_parser.js @@ -464,6 +464,7 @@ shaka.text.VttTextParser = class { payload = VttTextParser.replaceKaraokeStylePayload_(payload); payload = VttTextParser.replaceVoiceStylePayload_(payload); + payload = VttTextParser.escapeInvalidChevrons_(payload); const xmlPayload = '' + payload + ''; let element; try { @@ -490,6 +491,32 @@ shaka.text.VttTextParser = class { } } + /** + * This method converts invalid > chevrons to HTML entities. + * It also removes < chevrons as per spec. + * + * @param {!string} input + * @return {string} + * @private + */ + static escapeInvalidChevrons_(input) { + // Used to map HTML entities to characters. + const htmlEscapes = { + '< ': '', + ' >': ' >', + }; + + const reEscapedHtml = /(< +>|<\s|\s>)/g; + const reHasEscapedHtml = RegExp(reEscapedHtml.source); + // This check is an optimization, since replace always makes a copy + if (input && reHasEscapedHtml.test(input)) { + return input.replace(reEscapedHtml, (entity) => { + return htmlEscapes[entity] || ''; + }); + } + return input || ''; + } + /** * Converts voice style tag to be valid for xml parsing * For example, diff --git a/test/text/vtt_text_parser_unit.js b/test/text/vtt_text_parser_unit.js index bc05369c6a..18943eca65 100644 --- a/test/text/vtt_text_parser_unit.js +++ b/test/text/vtt_text_parser_unit.js @@ -1100,8 +1100,28 @@ describe('VttTextParser', () => { { startTime: 110, endTime: 120, - payload: 'less or more < > in text', - nestedCues: [], + payload: '', + nestedCues: [ + { + startTime: 110, + endTime: 120, + payload: 'less or more > >in text >', + color: 'lime', + }, + ], + }, + { + startTime: 120, + endTime: 130, + payload: '', + nestedCues: [ + { + startTime: 120, + endTime: 130, + payload: 'arrow in --> text', + color: 'lime', + }, + ], }, ], 'WEBVTT\n\n' + @@ -1122,7 +1142,9 @@ describe('VttTextParser', () => { '00:01:40.000 --> 00:01:50.000\n' + 'forward slash 1/2 in text\n\n' + '00:01:50.000 --> 00:02:00.000\n' + - 'less or more < > in text', + 'less or more < > > < > >in text >\n\n' + + '00:02:00.000 --> 00:02:10.000\n' + + 'arrow in --> text', {periodStart: 0, segmentStart: 0, segmentEnd: 0, vttOffset: 0}); }); From 08cc34a5322a4fdbabe4d80cf6b1c2a1d473f794 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mathieu=20C=C3=B4t=C3=A9?= Date: Fri, 26 Jan 2024 09:29:25 -0500 Subject: [PATCH 02/64] fix: AC-3 audio codec support on Tizen (#6166) Fixes https://github.com/shaka-project/shaka-player/issues/6160 --- AUTHORS | 1 + CONTRIBUTORS | 1 + lib/polyfill/media_capabilities.js | 15 ++++++++++++++- lib/util/stream_utils.js | 10 +--------- 4 files changed, 17 insertions(+), 10 deletions(-) diff --git a/AUTHORS b/AUTHORS index 4e4bf4dbe8..74bff17d9e 100644 --- a/AUTHORS +++ b/AUTHORS @@ -60,6 +60,7 @@ Lucas Gabriel Sánchez Martin Stark Matthias Van Parijs Mattias Wadman +Mirego <*@mirego.com> Mohamed Rashid Morten Hansen Nick Desaulniers diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 7eb3701cc7..017b50a658 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -88,6 +88,7 @@ Loïc Raux Lucas Gabriel Sánchez Martin Stark Matias Russitto +Mathieu Côté Matthias Van Parijs Mattias Wadman Michelle Zhuo diff --git a/lib/polyfill/media_capabilities.js b/lib/polyfill/media_capabilities.js index 875c5f9f48..0b885f8fd8 100644 --- a/lib/polyfill/media_capabilities.js +++ b/lib/polyfill/media_capabilities.js @@ -191,10 +191,23 @@ shaka.polyfill.MediaCapabilities = class { const videoCapabilities = []; if (mediaCapkeySystemConfig.audio) { - const capability = { + let capability = { robustness: mediaCapkeySystemConfig.audio.robustness || '', contentType: mediaDecodingConfig.audio.contentType, }; + + // Some Tizen devices seem to misreport AC-3 support, but correctly + // report EC-3 support. So query EC-3 as a fallback for AC-3. + // See https://github.com/shaka-project/shaka-player/issues/2989 for + // details. + if (shaka.util.Platform.isTizen() && + mediaDecodingConfig.audio.contentType.includes('codecs="ac-3"')) { + capability = { + robustness: capability.robustness, + contentType: 'audio/mp4; codecs="ec-3"', + }; + } + audioCapabilities.push(capability); } diff --git a/lib/util/stream_utils.js b/lib/util/stream_utils.js index 048b6a4675..ddbe64fc7a 100644 --- a/lib/util/stream_utils.js +++ b/lib/util/stream_utils.js @@ -917,15 +917,7 @@ shaka.util.StreamUtils = class { return 'opus'; } - // Some Tizen devices seem to misreport AC-3 support, but correctly - // report EC-3 support. So query EC-3 as a fallback for AC-3. - // See https://github.com/shaka-project/shaka-player/issues/2989 for - // details. - if (shaka.util.Platform.isTizen()) { - return codecs.toLowerCase() == 'ac-3' ? 'ec-3' : codecs; - } else { - return codecs; - } + return codecs; } From eb1fef888b771588e05ff443d78f630a28f29bf0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Velad=20Galv=C3=A1n?= Date: Fri, 26 Jan 2024 18:39:10 +0100 Subject: [PATCH 03/64] fix: Fix wrong aspect ratio in transmuxed videos (#6170) Fixes https://github.com/shaka-project/shaka-player/issues/6168 --- lib/mss/mss_parser.js | 2 ++ lib/transmuxer/aac_transmuxer.js | 2 ++ lib/transmuxer/ac3_transmuxer.js | 2 ++ lib/transmuxer/ec3_transmuxer.js | 2 ++ lib/transmuxer/h264.js | 29 +++++++++++++++++++++++++++- lib/transmuxer/h265.js | 30 ++++++++++++++++++++++++----- lib/transmuxer/mp3_transmuxer.js | 2 ++ lib/transmuxer/ts_transmuxer.js | 12 ++++++++++++ lib/util/mp4_generator.js | 33 ++++++++++++++++++++++++++++++-- 9 files changed, 106 insertions(+), 8 deletions(-) diff --git a/lib/mss/mss_parser.js b/lib/mss/mss_parser.js index 87e75832eb..fe58d41242 100644 --- a/lib/mss/mss_parser.js +++ b/lib/mss/mss_parser.js @@ -661,6 +661,8 @@ shaka.mss.MssParser = class { videoNalus: videoNalus, audioConfig: new Uint8Array([]), videoConfig: new Uint8Array([]), + hSpacing: 0, + vSpacing: 0, data: null, // Data is not necessary for init segement. stream: stream, }; diff --git a/lib/transmuxer/aac_transmuxer.js b/lib/transmuxer/aac_transmuxer.js index feb0183ebe..97e29bede4 100644 --- a/lib/transmuxer/aac_transmuxer.js +++ b/lib/transmuxer/aac_transmuxer.js @@ -195,6 +195,8 @@ shaka.transmuxer.AacTransmuxer = class { videoNalus: [], audioConfig: new Uint8Array([]), videoConfig: new Uint8Array([]), + hSpacing: 0, + vSpacing: 0, data: { sequenceNumber: this.frameIndex_, baseMediaDecodeTime: baseMediaDecodeTime, diff --git a/lib/transmuxer/ac3_transmuxer.js b/lib/transmuxer/ac3_transmuxer.js index 061433ae36..dfedfe2196 100644 --- a/lib/transmuxer/ac3_transmuxer.js +++ b/lib/transmuxer/ac3_transmuxer.js @@ -184,6 +184,8 @@ shaka.transmuxer.Ac3Transmuxer = class { videoNalus: [], audioConfig: audioConfig, videoConfig: new Uint8Array([]), + hSpacing: 0, + vSpacing: 0, data: { sequenceNumber: this.frameIndex_, baseMediaDecodeTime: baseMediaDecodeTime, diff --git a/lib/transmuxer/ec3_transmuxer.js b/lib/transmuxer/ec3_transmuxer.js index 42c1402c81..388d12086a 100644 --- a/lib/transmuxer/ec3_transmuxer.js +++ b/lib/transmuxer/ec3_transmuxer.js @@ -184,6 +184,8 @@ shaka.transmuxer.Ec3Transmuxer = class { videoNalus: [], audioConfig: audioConfig, videoConfig: new Uint8Array([]), + hSpacing: 0, + vSpacing: 0, data: { sequenceNumber: this.frameIndex_, baseMediaDecodeTime: baseMediaDecodeTime, diff --git a/lib/transmuxer/h264.js b/lib/transmuxer/h264.js index 88f3e919e4..ad7f9cd879 100644 --- a/lib/transmuxer/h264.js +++ b/lib/transmuxer/h264.js @@ -20,7 +20,8 @@ shaka.transmuxer.H264 = class { * describes the properties of upcoming video frames. * * @param {!Array.} nalus - * @return {?{height: number, width: number, videoConfig: !Uint8Array}} + * @return {?{height: number, width: number, videoConfig: !Uint8Array, + * hSpacing: number, vSpacing: number}} */ static parseInfo(nalus) { const H264 = shaka.transmuxer.H264; @@ -129,6 +130,30 @@ shaka.transmuxer.H264 = class { frameCropBottomOffset = expGolombDecoder.readUnsignedExpGolomb(); } + let hSpacing = 1; + let vSpacing = 1; + + // vui_parameters_present_flag + if (expGolombDecoder.readBoolean()) { + // aspect_ratio_info_present_flag + if (expGolombDecoder.readBoolean()) { + const aspectRatioIdc = expGolombDecoder.readUnsignedByte(); + const hSpacingTable = [ + 1, 12, 10, 16, 40, 24, 20, 32, 80, 18, 15, 64, 160, 4, 3, 2, + ]; + const vSpacingTable = [ + 1, 11, 11, 11, 33, 11, 11, 11, 33, 11, 11, 33, 99, 3, 2, 1, + ]; + if (aspectRatioIdc > 0 && aspectRatioIdc < 16) { + hSpacing = hSpacingTable[aspectRatioIdc - 1]; + vSpacing = vSpacingTable[aspectRatioIdc - 1]; + } else if (aspectRatioIdc === 255) { + hSpacing = expGolombDecoder.readBits(16); + vSpacing = expGolombDecoder.readBits(16); + } + } + } + const height = ((2 - frameMbsOnlyFlag) * (picHeightInMapUnitsMinus1 + 1) * 16) - (frameCropTopOffset * 2) - (frameCropBottomOffset * 2); @@ -165,6 +190,8 @@ shaka.transmuxer.H264 = class { height, width, videoConfig, + hSpacing, + vSpacing, }; } diff --git a/lib/transmuxer/h265.js b/lib/transmuxer/h265.js index 601a9cc907..64cfd3e5b9 100644 --- a/lib/transmuxer/h265.js +++ b/lib/transmuxer/h265.js @@ -20,7 +20,8 @@ shaka.transmuxer.H265 = class { * describes the properties of upcoming video frames. * * @param {!Array.} nalus - * @return {?{height: number, width: number, videoConfig: !Uint8Array}} + * @return {?{height: number, width: number, videoConfig: !Uint8Array, + * hSpacing: number, vSpacing: number}} */ static parseInfo(nalus) { const H265 = shaka.transmuxer.H265; @@ -87,6 +88,8 @@ shaka.transmuxer.H265 = class { height: spsConfiguration.height, width: spsConfiguration.width, videoConfig, + hSpacing: spsConfiguration.sarWidth, + vSpacing: spsConfiguration.sarHeight, }; } @@ -298,6 +301,8 @@ shaka.transmuxer.H265 = class { } } let defaultDisplayWindowFlag = false; // for calc offset + let sarWidth = 1; + let sarHeight = 1; let minSpatialSegmentationIdc = 0; // for hvcC gb.readBoolean(); // sps_temporal_mvp_enabled_flag gb.readBoolean(); // strong_intra_smoothing_enabled_flag @@ -306,9 +311,18 @@ shaka.transmuxer.H265 = class { const aspectRatioInfoPresentFlag = gb.readBoolean(); if (aspectRatioInfoPresentFlag) { const aspectRatioIdc = gb.readUnsignedByte(); - if (aspectRatioIdc === 255) { - gb.readBits(16); // sar_width - gb.readBits(16); // sar_height + const sarWidthTable = [ + 1, 12, 10, 16, 40, 24, 20, 32, 80, 18, 15, 64, 160, 4, 3, 2, + ]; + const sarHeightTable = [ + 1, 11, 11, 11, 33, 11, 11, 11, 33, 11, 11, 33, 99, 3, 2, 1, + ]; + if (aspectRatioIdc > 0 && aspectRatioIdc < 16) { + sarWidth = sarWidthTable[aspectRatioIdc - 1]; + sarHeight = sarHeightTable[aspectRatioIdc - 1]; + } else if (aspectRatioIdc === 255) { + sarWidth = gb.readBits(16); + sarHeight = gb.readBits(16); } } const overscanInfoPresentFlag = gb.readBoolean(); @@ -459,6 +473,8 @@ shaka.transmuxer.H265 = class { bitDepthChromaMinus8, width: codecWidth, height: codecHeight, + sarWidth: sarWidth, + sarHeight: sarHeight, }; } @@ -773,7 +789,9 @@ shaka.transmuxer.H265.VPSConfiguration; * bitDepthLumaMinus8: number, * bitDepthChromaMinus8: number, * width: number, - * height: number + * height: number, + * sarWidth: number, + * sarHeight: number * }} * * @property {number} generalProfileSpace @@ -797,6 +815,8 @@ shaka.transmuxer.H265.VPSConfiguration; * @property {number} bitDepthChromaMinus8 * @property {number} width * @property {number} height + * @property {number} sarWidth + * @property {number} sarHeight */ shaka.transmuxer.H265.SPSConfiguration; diff --git a/lib/transmuxer/mp3_transmuxer.js b/lib/transmuxer/mp3_transmuxer.js index a21ca22960..5cb2e3bae9 100644 --- a/lib/transmuxer/mp3_transmuxer.js +++ b/lib/transmuxer/mp3_transmuxer.js @@ -176,6 +176,8 @@ shaka.transmuxer.Mp3Transmuxer = class { videoNalus: [], audioConfig: new Uint8Array([]), videoConfig: new Uint8Array([]), + hSpacing: 0, + vSpacing: 0, data: { sequenceNumber: this.frameIndex_, baseMediaDecodeTime: baseMediaDecodeTime, diff --git a/lib/transmuxer/ts_transmuxer.js b/lib/transmuxer/ts_transmuxer.js index 2af666a3e7..7008541e76 100644 --- a/lib/transmuxer/ts_transmuxer.js +++ b/lib/transmuxer/ts_transmuxer.js @@ -409,6 +409,8 @@ shaka.transmuxer.TsTransmuxer = class { videoNalus: [], audioConfig: new Uint8Array([]), videoConfig: new Uint8Array([]), + hSpacing: 0, + vSpacing: 0, data: { sequenceNumber: this.frameIndex_, baseMediaDecodeTime: baseMediaDecodeTime, @@ -500,6 +502,8 @@ shaka.transmuxer.TsTransmuxer = class { videoNalus: [], audioConfig: audioConfig, videoConfig: new Uint8Array([]), + hSpacing: 0, + vSpacing: 0, data: { sequenceNumber: this.frameIndex_, baseMediaDecodeTime: baseMediaDecodeTime, @@ -591,6 +595,8 @@ shaka.transmuxer.TsTransmuxer = class { videoNalus: [], audioConfig: audioConfig, videoConfig: new Uint8Array([]), + hSpacing: 0, + vSpacing: 0, data: { sequenceNumber: this.frameIndex_, baseMediaDecodeTime: baseMediaDecodeTime, @@ -677,6 +683,8 @@ shaka.transmuxer.TsTransmuxer = class { videoNalus: [], audioConfig: new Uint8Array([]), videoConfig: new Uint8Array([]), + hSpacing: 0, + vSpacing: 0, data: { sequenceNumber: this.frameIndex_, baseMediaDecodeTime: baseMediaDecodeTime, @@ -769,6 +777,8 @@ shaka.transmuxer.TsTransmuxer = class { videoNalus: [], audioConfig: new Uint8Array([]), videoConfig: info.videoConfig, + hSpacing: info.hSpacing, + vSpacing: info.vSpacing, data: { sequenceNumber: this.frameIndex_, baseMediaDecodeTime: baseMediaDecodeTime, @@ -861,6 +871,8 @@ shaka.transmuxer.TsTransmuxer = class { videoNalus: [], audioConfig: new Uint8Array([]), videoConfig: info.videoConfig, + hSpacing: info.hSpacing, + vSpacing: info.vSpacing, data: { sequenceNumber: this.frameIndex_, baseMediaDecodeTime: baseMediaDecodeTime, diff --git a/lib/util/mp4_generator.js b/lib/util/mp4_generator.js index b8d72cacdc..e151989a17 100644 --- a/lib/util/mp4_generator.js +++ b/lib/util/mp4_generator.js @@ -371,12 +371,13 @@ shaka.util.Mp4Generator = class { ]); let boxName = 'avc1'; + const paspBox = this.pasp_(streamInfo); let sinfBox = new Uint8Array([]); if (streamInfo.encrypted) { sinfBox = this.sinf_(streamInfo); boxName = 'encv'; } - return Mp4Generator.box(boxName, avc1Bytes, avcCBox, sinfBox); + return Mp4Generator.box(boxName, avc1Bytes, avcCBox, paspBox, sinfBox); } /** @@ -500,12 +501,34 @@ shaka.util.Mp4Generator = class { ]); let boxName = 'hvc1'; + const paspBox = this.pasp_(streamInfo); let sinfBox = new Uint8Array([]); if (streamInfo.encrypted) { sinfBox = this.sinf_(streamInfo); boxName = 'encv'; } - return Mp4Generator.box(boxName, hvc1Bytes, hvcCBox, sinfBox); + return Mp4Generator.box(boxName, hvc1Bytes, hvcCBox, paspBox, sinfBox); + } + + /** + * Generate a PASP box + * + * @param {shaka.util.Mp4Generator.StreamInfo} streamInfo + * @return {!Uint8Array} + * @private + */ + pasp_(streamInfo) { + if (!streamInfo.hSpacing && !streamInfo.vSpacing) { + return new Uint8Array([]); + } + const Mp4Generator = shaka.util.Mp4Generator; + const hSpacing = streamInfo.hSpacing; + const vSpacing = streamInfo.vSpacing; + const bytes = new Uint8Array([ + ...this.breakNumberIntoBytes_(hSpacing, 4), // hSpacing + ...this.breakNumberIntoBytes_(vSpacing, 4), // vSpacing + ]); + return Mp4Generator.box('pasp', bytes); } /** @@ -1301,6 +1324,8 @@ shaka.util.Mp4Generator.DINF_ = new Uint8Array([]); * videoNalus: !Array., * audioConfig: !Uint8Array, * videoConfig: !Uint8Array, + * hSpacing: number, + * vSpacing: number, * data: ?shaka.util.Mp4Generator.Data, * stream: !shaka.extern.Stream * }} @@ -1325,6 +1350,10 @@ shaka.util.Mp4Generator.DINF_ = new Uint8Array([]); * The stream's audio config. * @property {!Uint8Array} videoConfig * The stream's video config. + * @property {number} hSpacing + * The stream's video horizontal spacing of pixels. + * @property {number} vSpacing + * The stream's video vertial spacing of pixels. * @property {?shaka.util.Mp4Generator.Data} data * The stream's data. * @property {!shaka.extern.Stream} stream From a8ab0c824b7e777e429401c294b7629d23cc0f78 Mon Sep 17 00:00:00 2001 From: Gary Katsevman Date: Mon, 29 Jan 2024 02:35:17 -0500 Subject: [PATCH 04/64] feat: prefetch audio languages. (#6139) Closes #6128 --- demo/config.js | 46 ++-- externs/shaka/player.js | 16 +- lib/media/segment_index.js | 21 +- lib/media/segment_prefetch.js | 186 ++++++++++---- lib/media/streaming_engine.js | 181 ++++++++++++-- lib/util/player_configuration.js | 3 + test/media/segment_prefetch_unit.js | 121 ++++++++-- test/media/streaming_engine_unit.js | 306 +++++++++++++++++++----- test/test/util/fake_segment_prefetch.js | 67 +++++- test/test/util/streaming_engine_util.js | 100 ++++++-- 10 files changed, 846 insertions(+), 201 deletions(-) diff --git a/demo/config.js b/demo/config.js index a5dee05560..d658ca023c 100644 --- a/demo/config.js +++ b/demo/config.js @@ -444,7 +444,19 @@ shakaDemo.Config = class { .addBoolInput_('Parse PRFT box', 'streaming.parsePrftBox') .addNumberInput_('Segment Prefetch Limit', - 'streaming.segmentPrefetchLimit') + 'streaming.segmentPrefetchLimit', + /* canBeDecimal= */ false, + /* canBeZero= */ true, + /* canBeUnset= */ true) + .addCustomTextInput_('Prefetch audio languages', (input) => { + shakaDemoMain.configure( + 'streaming.prefetchAudioLanguages', + input.value.split(',').filter(Boolean)); + }) + .addBoolInput_('Disable Audio Prefetch', + 'streaming.disableAudioPrefetch') + .addBoolInput_('Disable Video Prefetch', + 'streaming.disableVideoPrefetch') .addBoolInput_('Live Sync', 'streaming.liveSync') .addNumberInput_('Max latency for live sync', 'streaming.liveSyncMaxLatency', @@ -775,27 +787,25 @@ shakaDemo.Config = class { addNumberInput_(name, valueName, canBeDecimal = false, canBeZero = true, canBeUnset = false, tooltipMessage) { const onChange = (input) => { - shakaDemoMain.resetConfiguration(valueName); - shakaDemoMain.remakeHash(); if (input.value == 'Infinity') { shakaDemoMain.configure(valueName, Infinity); - shakaDemoMain.remakeHash(); - return; - } - if (input.value == '' && canBeUnset) { - return; - } - const valueAsNumber = Number(input.value); - if (valueAsNumber == 0 && !canBeZero) { - return; - } - if (!isNaN(valueAsNumber)) { - if (Math.floor(valueAsNumber) != valueAsNumber && !canBeDecimal) { - return; + } else if (input.value == '' && canBeUnset) { + shakaDemoMain.resetConfiguration(valueName); + } else { + const valueAsNumber = Number(input.value); + if (valueAsNumber == 0 && !canBeZero) { + shakaDemoMain.resetConfiguration(valueName); + } else if (isNaN(valueAsNumber)) { + shakaDemoMain.resetConfiguration(valueName); + } else { + if (Math.floor(valueAsNumber) != valueAsNumber && !canBeDecimal) { + shakaDemoMain.resetConfiguration(valueName); + } else { + shakaDemoMain.configure(valueName, valueAsNumber); + } } - shakaDemoMain.configure(valueName, valueAsNumber); - shakaDemoMain.remakeHash(); } + shakaDemoMain.remakeHash(); }; this.createRow_(name, tooltipMessage); this.latestInput_ = new shakaDemo.NumberInput( diff --git a/externs/shaka/player.js b/externs/shaka/player.js index 60db46f18c..30e74dacf6 100644 --- a/externs/shaka/player.js +++ b/externs/shaka/player.js @@ -1159,6 +1159,9 @@ shaka.extern.ManifestConfiguration; * maxDisabledTime: number, * parsePrftBox: boolean, * segmentPrefetchLimit: number, + * prefetchAudioLanguages: !Array, + * disableAudioPrefetch: boolean, + * disableVideoPrefetch: boolean, * liveSync: boolean, * liveSyncMaxLatency: number, * liveSyncPlaybackRate: number, @@ -1279,11 +1282,22 @@ shaka.extern.ManifestConfiguration; * start date will not change, and would save parsing the segment multiple * times needlessly. * Defaults to false. - * @property {boolean} segmentPrefetchLimit + * @property {number} segmentPrefetchLimit * The maximum number of segments for each active stream to be prefetched * ahead of playhead in parallel. * If 0, the segments will be fetched sequentially. * Defaults to 0. + * @property {!Array} prefetchAudioLanguages + * The audio languages to prefetch. + * Defaults to an empty array. + * @property {boolean} disableAudioPrefetch + * If set and prefetch limit is defined, it will prevent from prefetching data + * for audio. + * Defaults to false. + * @property {boolean} disableVideoPrefetch + * If set and prefetch limit is defined, it will prevent from prefetching data + * for video. + * Defaults to false. * @property {boolean} liveSync * Enable the live stream sync against the live edge by changing the playback * rate. Defaults to false. diff --git a/lib/media/segment_index.js b/lib/media/segment_index.js index 32b4999ad8..7d7a6abcbe 100644 --- a/lib/media/segment_index.js +++ b/lib/media/segment_index.js @@ -434,10 +434,11 @@ shaka.media.SegmentIndex = class { * Playlist will contain at least one independent frame." * * @param {number} time + * @param {boolean=} allowNonIndepedent * @return {?shaka.media.SegmentIterator} * @export */ - getIteratorForTime(time) { + getIteratorForTime(time, allowNonIndepedent = false) { let index = this.find(time); if (index == null) { return null; @@ -455,14 +456,16 @@ shaka.media.SegmentIndex = class { let r = ref.partialReferences[i]; // Note that a segment ends immediately before the end time. if ((time >= r.startTime) && (time < r.endTime)) { - // Find an independent partial segment by moving backwards. - while (i && !r.isIndependent()) { - i--; - r = ref.partialReferences[i]; - } - if (!r.isIndependent()) { - shaka.log.alwaysError('No independent partial segment found!'); - return null; + if (!allowNonIndepedent) { + // Find an independent partial segment by moving backwards. + while (i && (!r.isIndependent())) { + i--; + r = ref.partialReferences[i]; + } + if (!r.isIndependent()) { + shaka.log.alwaysError('No independent partial segment found!'); + return null; + } } // Call to next() should move the partial segment, not the full // segment. diff --git a/lib/media/segment_prefetch.js b/lib/media/segment_prefetch.js index 0e0b093150..e7c5aa90b7 100644 --- a/lib/media/segment_prefetch.js +++ b/lib/media/segment_prefetch.js @@ -25,8 +25,9 @@ shaka.media.SegmentPrefetch = class { * @param {number} prefetchLimit * @param {shaka.extern.Stream} stream * @param {shaka.media.SegmentPrefetch.FetchDispatcher} fetchDispatcher + * @param {boolean} deleteOnGet */ - constructor(prefetchLimit, stream, fetchDispatcher) { + constructor(prefetchLimit, stream, fetchDispatcher, deleteOnGet = true) { /** @private {number} */ this.prefetchLimit_ = prefetchLimit; @@ -39,44 +40,59 @@ shaka.media.SegmentPrefetch = class { /** @private {shaka.media.SegmentPrefetch.FetchDispatcher} */ this.fetchDispatcher_ = fetchDispatcher; + /** @private {boolean} */ + this.deleteOnGet_ = deleteOnGet; + /** * @private {!Map.< - * !(shaka.media.SegmentReference|shaka.media.InitSegmentReference), + * !(shaka.media.SegmentReference), * !shaka.media.SegmentPrefetchOperation>} */ this.segmentPrefetchMap_ = new Map(); + + /** + * @private {!Map.< + * !(shaka.media.InitSegmentReference), + * !shaka.media.SegmentPrefetchOperation>} + */ + this.initSegmentPrefetchMap_ = new Map(); } /** - * Fetch next segments ahead of current segment. + * @return {number} + */ + getLastKnownPosition() { + return this.prefetchPosTime_; + } + + /** + * Fetch next segments ahead of current time. * - * @param {(!shaka.media.SegmentReference)} startReference + * @param {number} currTime * @param {boolean=} skipFirst * @public */ - prefetchSegments(startReference, skipFirst = false) { + prefetchSegmentsByTime(currTime, skipFirst = false) { goog.asserts.assert(this.prefetchLimit_ > 0, 'SegmentPrefetch can not be used when prefetchLimit <= 0.'); const logPrefix = shaka.media.SegmentPrefetch.logPrefix_(this.stream_); if (!this.stream_.segmentIndex) { - shaka.log.info(logPrefix, 'missing segmentIndex'); + shaka.log.debug(logPrefix, 'missing segmentIndex'); return; } - const currTime = startReference.startTime; const maxTime = Math.max(currTime, this.prefetchPosTime_); - const iterator = this.stream_.segmentIndex.getIteratorForTime(maxTime); + const iterator = this.stream_.segmentIndex.getIteratorForTime( + maxTime, /* allowNonIndepedent= */ true); if (!iterator) { return; } - let reference = startReference; + let reference = iterator.next().value; if (skipFirst) { reference = iterator.next().value; - if (reference && - reference.startTime == startReference.startTime && - reference.endTime == startReference.endTime) { - reference = null; - } + } + if (!reference) { + return; } while (this.segmentPrefetchMap_.size < this.prefetchLimit_ && reference != null) { @@ -90,6 +106,9 @@ shaka.media.SegmentPrefetch = class { shaka.media.SegmentReference.Status.MISSING) { prefetchAllowed = false; } + if (prefetchAllowed && reference.initSegmentReference) { + this.prefetchInitSegment_(reference.initSegmentReference); + } if (prefetchAllowed && !this.segmentPrefetchMap_.has(reference)) { const segmentPrefetchOperation = new shaka.media.SegmentPrefetchOperation(this.fetchDispatcher_); @@ -103,33 +122,33 @@ shaka.media.SegmentPrefetch = class { } reference = iterator.next().value; } + this.clearInitSegments_(); } /** * Fetch init segment. * * @param {!shaka.media.InitSegmentReference} initSegmentReference - * @public + * @private */ - prefetchInitSegment(initSegmentReference) { + prefetchInitSegment_(initSegmentReference) { goog.asserts.assert(this.prefetchLimit_ > 0, 'SegmentPrefetch can not be used when prefetchLimit <= 0.'); const logPrefix = shaka.media.SegmentPrefetch.logPrefix_(this.stream_); if (!this.stream_.segmentIndex) { - shaka.log.info(logPrefix, 'missing segmentIndex'); + shaka.log.debug(logPrefix, 'missing segmentIndex'); return; } - if (this.segmentPrefetchMap_.size < this.prefetchLimit_) { - if (!this.segmentPrefetchMap_.has(initSegmentReference)) { - const segmentPrefetchOperation = - new shaka.media.SegmentPrefetchOperation(this.fetchDispatcher_); - segmentPrefetchOperation.dispatchFetch( - initSegmentReference, this.stream_); - this.segmentPrefetchMap_.set( - initSegmentReference, segmentPrefetchOperation); - } + // init segments are ignored from the prefetch limit + if (!this.initSegmentPrefetchMap_.has(initSegmentReference)) { + const segmentPrefetchOperation = + new shaka.media.SegmentPrefetchOperation(this.fetchDispatcher_); + segmentPrefetchOperation.dispatchFetch( + initSegmentReference, this.stream_); + this.initSegmentPrefetchMap_.set( + initSegmentReference, segmentPrefetchOperation); } } @@ -147,22 +166,29 @@ shaka.media.SegmentPrefetch = class { const logPrefix = shaka.media.SegmentPrefetch.logPrefix_(this.stream_); - if (this.segmentPrefetchMap_.has(reference)) { - const segmentPrefetchOperation = this.segmentPrefetchMap_.get(reference); + let prefetchMap = this.segmentPrefetchMap_; + if (reference instanceof shaka.media.InitSegmentReference) { + prefetchMap = this.initSegmentPrefetchMap_; + } + + if (prefetchMap.has(reference)) { + const segmentPrefetchOperation = prefetchMap.get(reference); if (streamDataCallback) { segmentPrefetchOperation.setStreamDataCallback(streamDataCallback); } - this.segmentPrefetchMap_.delete(reference); + if (this.deleteOnGet_) { + prefetchMap.delete(reference); + } if (reference instanceof shaka.media.SegmentReference) { shaka.log.debug( logPrefix, 'reused prefetched segment at time:', reference.startTime, - 'mapSize', this.segmentPrefetchMap_.size); + 'mapSize', prefetchMap.size); } else { shaka.log.debug( logPrefix, 'reused prefetched init segment at time, mapSize', - this.segmentPrefetchMap_.size); + prefetchMap.size); } return segmentPrefetchOperation.getOperation(); } else { @@ -170,33 +196,72 @@ shaka.media.SegmentPrefetch = class { shaka.log.debug( logPrefix, 'missed segment at time:', reference.startTime, - 'mapSize', this.segmentPrefetchMap_.size); + 'mapSize', prefetchMap.size); } else { shaka.log.debug( logPrefix, 'missed init segment at time, mapSize', - this.segmentPrefetchMap_.size); + prefetchMap.size); } return null; } } + /** + * Clear All Helper + * @private + */ + clearMap_(map) { + for (const reference of map.keys()) { + if (reference) { + this.abortPrefetchedSegment_(reference); + } + } + } + /** * Clear all segment data. * @public */ clearAll() { - if (this.segmentPrefetchMap_.size === 0) { - return; - } + this.clearMap_(this.segmentPrefetchMap_); + this.clearMap_(this.initSegmentPrefetchMap_); const logPrefix = shaka.media.SegmentPrefetch.logPrefix_(this.stream_); - for (const reference of this.segmentPrefetchMap_.keys()) { - if (reference) { - this.abortPrefetchedSegment_(reference); + shaka.log.debug(logPrefix, 'cleared all'); + this.prefetchPosTime_ = 0; + } + + /** + * @param {number} time + */ + evict(time) { + for (const ref of this.segmentPrefetchMap_.keys()) { + if (time > ref.endTime) { + this.abortPrefetchedSegment_(ref); + } + } + this.clearInitSegments_(); + } + + /** + * Remove all init segments that don't have associated segments in + * the segment prefetch map. + * By default, with delete on get, the init segments should get removed as + * they are used. With deleteOnGet set to false, we need to clear them + * every so often once the segments that are associated with each init segment + * is no longer prefetched. + * @private + */ + clearInitSegments_() { + const segmentReferences = Array.from(this.segmentPrefetchMap_.keys()); + for (const initSegmentReference of this.initSegmentPrefetchMap_.keys()) { + // if no segment references this init segment, we should remove it. + if (!segmentReferences.some( + (segmentReference) => + segmentReference.initSegmentReference === initSegmentReference)) { + this.abortPrefetchedSegment_(initSegmentReference); } } - shaka.log.info(logPrefix, 'cleared all'); - this.prefetchPosTime_ = 0; } /** @@ -208,6 +273,9 @@ shaka.media.SegmentPrefetch = class { resetLimit(newPrefetchLimit) { goog.asserts.assert(newPrefetchLimit >= 0, 'The new prefetch limit must be >= 0.'); + + const logPrefix = shaka.media.SegmentPrefetch.logPrefix_(this.stream_); + shaka.log.debug(logPrefix, 'resetting prefetch limit to', newPrefetchLimit); this.prefetchLimit_ = newPrefetchLimit; const keyArr = Array.from(this.segmentPrefetchMap_.keys()); while (keyArr.length > newPrefetchLimit) { @@ -218,18 +286,39 @@ shaka.media.SegmentPrefetch = class { } } + /** + * Update deleteOnGet. + * @param {boolean} newDeleteOnGet + * @public + */ + deleteOnGet(newDeleteOnGet) { + this.deleteOnGet_ = newDeleteOnGet; + } + /** * Called by Streaming Engine when switching variant. * @param {shaka.extern.Stream} stream * @public */ switchStream(stream) { + goog.asserts.assert(this.deleteOnGet_, + 'switchStream should only be used if deleteOnGet is true'); + if (stream && stream !== this.stream_) { this.clearAll(); this.stream_ = stream; } } + /** + * Get the current stream. + * @public + * @return {shaka.extern.Stream} + */ + getStream() { + return this.stream_; + } + /** * Remove a segment from prefetch map and abort it. * @param {!(shaka.media.SegmentReference|shaka.media.InitSegmentReference)} @@ -238,16 +327,23 @@ shaka.media.SegmentPrefetch = class { */ abortPrefetchedSegment_(reference) { const logPrefix = shaka.media.SegmentPrefetch.logPrefix_(this.stream_); - const segmentPrefetchOperation = this.segmentPrefetchMap_.get(reference); - this.segmentPrefetchMap_.delete(reference); + + let prefetchMap = this.segmentPrefetchMap_; + if (reference instanceof shaka.media.InitSegmentReference) { + prefetchMap = this.initSegmentPrefetchMap_; + } + + const segmentPrefetchOperation = prefetchMap.get(reference); + prefetchMap.delete(reference); + if (segmentPrefetchOperation) { segmentPrefetchOperation.abort(); if (reference instanceof shaka.media.SegmentReference) { - shaka.log.info( + shaka.log.debug( logPrefix, 'pop and abort prefetched segment at time:', reference.startTime); } else { - shaka.log.info(logPrefix, 'pop and abort prefetched init segment'); + shaka.log.debug(logPrefix, 'pop and abort prefetched init segment'); } } } diff --git a/lib/media/streaming_engine.js b/lib/media/streaming_engine.js index 09d984cce9..7d98a0b0d3 100644 --- a/lib/media/streaming_engine.js +++ b/lib/media/streaming_engine.js @@ -27,6 +27,7 @@ goog.require('shaka.util.Error'); goog.require('shaka.util.FakeEvent'); goog.require('shaka.util.IDestroyable'); goog.require('shaka.util.Id3Utils'); +goog.require('shaka.util.LanguageUtils'); goog.require('shaka.util.ManifestParserUtils'); goog.require('shaka.util.MimeUtils'); goog.require('shaka.util.Mp4BoxParsers'); @@ -122,6 +123,11 @@ shaka.media.StreamingEngine = class { /** @private {number} */ this.lastMediaSourceReset_ = Date.now() / 1000; + + /** + * @private {!Map} + */ + this.audioPrefetchMap_ = new Map(); } /** @override */ @@ -140,10 +146,14 @@ shaka.media.StreamingEngine = class { this.cancelUpdate_(state); aborts.push(this.abortOperations_(state)); } + for (const prefetch of this.audioPrefetchMap_.values()) { + prefetch.clearAll(); + } await Promise.all(aborts); this.mediaStates_.clear(); + this.audioPrefetchMap_.clear(); this.playerInterface_ = null; this.manifest_ = null; @@ -180,6 +190,32 @@ shaka.media.StreamingEngine = class { this.failureCallbackBackoff_ = new shaka.net.Backoff(failureRetryParams, autoReset); + const ContentType = shaka.util.ManifestParserUtils.ContentType; + + // disable audio segment prefetch if this is now set + if (config.disableAudioPrefetch) { + const state = this.mediaStates_.get(ContentType.AUDIO); + if (state && state.segmentPrefetch) { + state.segmentPrefetch.clearAll(); + state.segmentPrefetch = null; + } + + for (const stream of this.audioPrefetchMap_.keys()) { + const prefetch = this.audioPrefetchMap_.get(stream); + prefetch.clearAll(); + this.audioPrefetchMap_.delete(stream); + } + } + + // disable video segment prefetch if this is now set + if (config.disableVideoPrefetch) { + const state = this.mediaStates_.get(ContentType.VIDEO); + if (state && state.segmentPrefetch) { + state.segmentPrefetch.clearAll(); + state.segmentPrefetch = null; + } + } + // Allow configuring the segment prefetch in middle of the playback. for (const type of this.mediaStates_.keys()) { const state = this.mediaStates_.get(type); @@ -194,6 +230,10 @@ shaka.media.StreamingEngine = class { state.segmentPrefetch = this.createSegmentPrefetch_(state.stream); } } + + if (!config.disableAudioPrefetch) { + this.updatePrefetchMapForAudio_(); + } } @@ -472,7 +512,9 @@ shaka.media.StreamingEngine = class { return; } - if (mediaState.segmentPrefetch) { + if (this.audioPrefetchMap_.has(stream)) { + mediaState.segmentPrefetch = this.audioPrefetchMap_.get(stream); + } else if (mediaState.segmentPrefetch) { mediaState.segmentPrefetch.switchStream(stream); } @@ -487,8 +529,11 @@ shaka.media.StreamingEngine = class { } // Releases the segmentIndex of the old stream. - if (mediaState.stream.closeSegmentIndex) { - mediaState.stream.closeSegmentIndex(); + // Do not close segment indexes we are prefetching. + if (!this.audioPrefetchMap_.has(mediaState.stream)) { + if (mediaState.stream.closeSegmentIndex) { + mediaState.stream.closeSegmentIndex(); + } } mediaState.stream = stream; @@ -896,12 +941,32 @@ shaka.media.StreamingEngine = class { * @private */ createSegmentPrefetch_(stream) { + const ContentType = shaka.util.ManifestParserUtils.ContentType; if ( - stream.type !== shaka.util.ManifestParserUtils.ContentType.VIDEO && - stream.type !== shaka.util.ManifestParserUtils.ContentType.AUDIO + stream.type !== ContentType.VIDEO && + stream.type !== ContentType.AUDIO ) { return null; } + if (stream.type === ContentType.VIDEO && + this.config_.disableVideoPrefetch) { + return null; + } + if (stream.type === ContentType.AUDIO && + this.config_.disableAudioPrefetch) { + return null; + } + if (this.audioPrefetchMap_.has(stream)) { + return this.audioPrefetchMap_.get(stream); + } + const type = /** @type {!shaka.util.ManifestParserUtils.ContentType} */ + (stream.type); + const mediaState = this.mediaStates_.get(type); + const currentSegmentPrefetch = mediaState && mediaState.segmentPrefetch; + if (currentSegmentPrefetch && + stream === currentSegmentPrefetch.getStream()) { + return currentSegmentPrefetch; + } if (this.config_.segmentPrefetchLimit > 0) { return new shaka.media.SegmentPrefetch( this.config_.segmentPrefetchLimit, @@ -914,6 +979,80 @@ shaka.media.StreamingEngine = class { return null; } + /** + * Populates the prefetch map depending on the configuration + * @private + */ + updatePrefetchMapForAudio_() { + const prefetchLimit = this.config_.segmentPrefetchLimit; + const prefetchLanguages = this.config_.prefetchAudioLanguages; + const LanguageUtils = shaka.util.LanguageUtils; + + for (const variant of this.manifest_.variants) { + if (!variant.audio) { + continue; + } + + if (this.audioPrefetchMap_.has(variant.audio)) { + // if we already have a segment prefetch, + // update it's prefetch limit and if the new limit isn't positive, + // remove the segment prefetch from our prefetch map. + const prefetch = this.audioPrefetchMap_.get(variant.audio); + prefetch.resetLimit(prefetchLimit); + if (!(prefetchLimit > 0) || + !prefetchLanguages.some( + (lang) => LanguageUtils.areLanguageCompatible( + variant.audio.language, lang)) + ) { + // if we're here, we are switching back to single stream prefetch, + // so we want to switch back to delete on get, even if the prefetch + // may end up getting deleted below. + prefetch.deleteOnGet(true); + const type = /** @type {!shaka.util.ManifestParserUtils.ContentType}*/ + (variant.audio.type); + const mediaState = this.mediaStates_.get(type); + const currentSegmentPrefetch = mediaState && + mediaState.segmentPrefetch; + // if this prefetch isn't the current one, we want to clear it + if (prefetch !== currentSegmentPrefetch) { + prefetch.clearAll(); + } + this.audioPrefetchMap_.delete(variant.audio); + } + continue; + } + + // don't try to create a new segment prefetch if the limit isn't positive. + if (prefetchLimit <= 0) { + continue; + } + + // only create a segment prefetch if its language is configured + // to be prefetched + if (!prefetchLanguages.some( + (lang) => LanguageUtils.areLanguageCompatible( + variant.audio.language, lang))) { + continue; + } + + // use the helper to create a segment prefetch to ensure that existing + // objects are reused. + const segmentPrefetch = this.createSegmentPrefetch_(variant.audio); + segmentPrefetch.deleteOnGet(false); + + // if a segment prefetch wasn't created, skip the rest + if (!segmentPrefetch) { + continue; + } + + if (!variant.audio.segmentIndex) { + variant.audio.createSegmentIndex(); + } + + this.audioPrefetchMap_.set(variant.audio, segmentPrefetch); + } + } + /** * Sets the MediaSource's duration. */ @@ -1072,6 +1211,16 @@ shaka.media.StreamingEngine = class { // Compute how far we've buffered ahead of the playhead. const presentationTime = this.playerInterface_.getPresentationTime(); + if (mediaState.type === ContentType.AUDIO) { + // evict all prefetched segments that are before the presentationTime + for (const stream of this.audioPrefetchMap_.keys()) { + const prefetch = this.audioPrefetchMap_.get(stream); + prefetch.evict(presentationTime); + prefetch.prefetchSegmentsByTime(presentationTime, + /* fetchInit= */ true); + } + } + // Get the next timestamp we need. const timeNeeded = this.getTimeNeeded_(mediaState, presentationTime); shaka.log.v2(logPrefix, 'timeNeeded=' + timeNeeded); @@ -1175,14 +1324,9 @@ shaka.media.StreamingEngine = class { return this.config_.updateIntervalSeconds; } - if (mediaState.segmentPrefetch && mediaState.segmentIterator) { - const initSegmentReference = reference.initSegmentReference; - if (initSegmentReference && (!mediaState.lastSegmentReference || - !shaka.media.InitSegmentReference.equal( - initSegmentReference, mediaState.lastInitSegmentReference))) { - mediaState.segmentPrefetch.prefetchInitSegment(initSegmentReference); - } - mediaState.segmentPrefetch.prefetchSegments(reference); + if (mediaState.segmentPrefetch && mediaState.segmentIterator && + !this.audioPrefetchMap_.has(mediaState.stream)) { + mediaState.segmentPrefetch.prefetchSegmentsByTime(reference.startTime); } const p = this.fetchAndAppend_(mediaState, presentationTime, reference); @@ -1396,8 +1540,8 @@ shaka.media.StreamingEngine = class { /* isChunkedData= */ true); if (mediaState.segmentPrefetch && mediaState.segmentIterator) { - mediaState.segmentPrefetch.prefetchSegments( - reference, /* skipFirst= */ true); + mediaState.segmentPrefetch.prefetchSegmentsByTime( + reference.startTime, /* skipFirst= */ true); } } } catch (error) { @@ -1437,8 +1581,8 @@ shaka.media.StreamingEngine = class { } if (mediaState.segmentPrefetch && mediaState.segmentIterator) { - mediaState.segmentPrefetch.prefetchSegments( - reference, /* skipFirst= */ true); + mediaState.segmentPrefetch.prefetchSegmentsByTime( + reference.startTime, /* skipFirst= */ true); } } else { if (this.config_.lowLatencyMode && !isReadableStreamSupported) { @@ -2324,7 +2468,8 @@ shaka.media.StreamingEngine = class { mediaState.segmentIterator = null; shaka.log.debug(logPrefix, 'clearing buffer'); - if (mediaState.segmentPrefetch) { + if (mediaState.segmentPrefetch && + !this.audioPrefetchMap_.has(mediaState.stream)) { mediaState.segmentPrefetch.clearAll(); } diff --git a/lib/util/player_configuration.js b/lib/util/player_configuration.js index fa2ec63f2e..2f4784bdf5 100644 --- a/lib/util/player_configuration.js +++ b/lib/util/player_configuration.js @@ -224,6 +224,9 @@ shaka.util.PlayerConfiguration = class { // When low latency streaming is enabled, segmentPrefetchLimit will // default to 2 if not specified. segmentPrefetchLimit: 0, + prefetchAudioLanguages: [], + disableAudioPrefetch: false, + disableVideoPrefetch: false, liveSync: false, liveSyncMaxLatency: 1, liveSyncPlaybackRate: 1.1, diff --git a/test/media/segment_prefetch_unit.js b/test/media/segment_prefetch_unit.js index 45c2512a4f..1f6de6f48f 100644 --- a/test/media/segment_prefetch_unit.js +++ b/test/media/segment_prefetch_unit.js @@ -51,9 +51,9 @@ describe('SegmentPrefetch', () => { ); }); - describe('prefetchSegments', () => { + describe('prefetchSegmentsByTime', () => { it('should prefetch next 3 segments', async () => { - segmentPrefetch.prefetchSegments(references[0]); + segmentPrefetch.prefetchSegmentsByTime(references[0].startTime); await expectSegmentsPrefetched(0); const op = segmentPrefetch.getPrefetchedSegment(references[3]); expect(op).toBeNull(); @@ -61,7 +61,7 @@ describe('SegmentPrefetch', () => { }); it('prefetch last segment if position is at the end', async () => { - segmentPrefetch.prefetchSegments(references[3]); + segmentPrefetch.prefetchSegmentsByTime(references[3].startTime); const op = segmentPrefetch.getPrefetchedSegment(references[3]); expect(op).toBeDefined(); const response = await op.promise; @@ -76,19 +76,62 @@ describe('SegmentPrefetch', () => { }); it('do not prefetch already fetched segment', async () => { - segmentPrefetch.prefetchSegments(references[1]); + segmentPrefetch.prefetchSegmentsByTime(references[1].startTime); // since 2 was alreay pre-fetched when prefetch 1, expect // no extra fetch is made. - segmentPrefetch.prefetchSegments(references[2]); + segmentPrefetch.prefetchSegmentsByTime(references[2].startTime); expect(fetchDispatcher).toHaveBeenCalledTimes(3); await expectSegmentsPrefetched(1); }); + + it('does prefetch init segment', async () => { + const references = [ + makeReference(uri('0.10'), 0, 10), + makeReference(uri('10.20'), 10, 20), + makeReference(uri('20.30'), 20, 30), + makeReference(uri('30.40'), 30, 40), + ]; + references[0].initSegmentReference = + new shaka.media.InitSegmentReference(() => ['init-0.mp4'], 0, 500); + references[1].initSegmentReference = + new shaka.media.InitSegmentReference(() => ['init-1.mp4'], 0, 500); + references[2].initSegmentReference = + new shaka.media.InitSegmentReference(() => ['init-2.mp4'], 0, 500); + references[3].initSegmentReference = + new shaka.media.InitSegmentReference(() => ['init-3.mp4'], 0, 500); + + stream = createStream(); + stream.segmentIndex = new shaka.media.SegmentIndex(references); + segmentPrefetch = new shaka.media.SegmentPrefetch( + 3, stream, Util.spyFunc(fetchDispatcher), + ); + + segmentPrefetch.prefetchSegmentsByTime(references[0].startTime); + + for (let i = 0; i < 3; i++) { + const op = segmentPrefetch.getPrefetchedSegment(references[i]); + expect(op).not.toBeNull(); + /* eslint-disable-next-line no-await-in-loop */ + const response = await op.promise; + const startTime = (i * 10); + expect(response.uri).toBe(uri(startTime + '.' + (startTime + 10))); + } + + for (let i = 0; i < 3; i++) { + const op = segmentPrefetch.getPrefetchedSegment( + references[i].initSegmentReference); + expect(op).not.toBeNull(); + } + // this is 6 to account for the init segments, + // which is not part of the prefetch limit + expect(fetchDispatcher).toHaveBeenCalledTimes(6); + }); }); describe('clearAll', () => { it('clears all prefetched segments', () => { - segmentPrefetch.prefetchSegments(references[0]); + segmentPrefetch.prefetchSegmentsByTime(references[0].startTime); segmentPrefetch.clearAll(); for (let i = 0; i < 3; i++) { const op = segmentPrefetch.getPrefetchedSegment(references[i]); @@ -98,14 +141,14 @@ describe('SegmentPrefetch', () => { }); it('resets time pos so prefetch can happen again', () => { - segmentPrefetch.prefetchSegments(references[3]); + segmentPrefetch.prefetchSegmentsByTime(references[3].startTime); segmentPrefetch.clearAll(); for (let i = 0; i < 3; i++) { const op = segmentPrefetch.getPrefetchedSegment(references[i]); expect(op).toBeNull(); } - segmentPrefetch.prefetchSegments(references[3]); + segmentPrefetch.prefetchSegmentsByTime(references[3].startTime); for (let i = 0; i < 3; i++) { const op = segmentPrefetch.getPrefetchedSegment(references[i]); expect(op).toBeNull(); @@ -115,9 +158,55 @@ describe('SegmentPrefetch', () => { }); }); + describe('evict', () => { + it('does not evict a segment that straddles the given time', async () => { + segmentPrefetch.deleteOnGet(false); + segmentPrefetch.prefetchSegmentsByTime(references[0].startTime); + segmentPrefetch.evict(5); + await expectSegmentsPrefetched(0); + for (let i = 0; i < 3; i++) { + const op = segmentPrefetch.getPrefetchedSegment(references[i]); + expect(op).toBeDefined(); + // eslint-disable-next-line no-await-in-loop + const response = await op.promise; + const startTime = (i * 10); + expect(response.uri).toBe(uri(startTime + '.' + (startTime + 10))); + } + + expect(fetchDispatcher).toHaveBeenCalledTimes(3); + }); + + it('segments that end before the provided time', async () => { + segmentPrefetch.deleteOnGet(false); + segmentPrefetch.prefetchSegmentsByTime(references[0].startTime); + segmentPrefetch.evict(21); + for (let i = 0; i < 2; i++) { + const op = segmentPrefetch.getPrefetchedSegment(references[i]); + expect(op).toBeNull(); + } + await expectSegmentsPrefetched(2, 1); + const op = segmentPrefetch.getPrefetchedSegment(references[2]); + expect(op).toBeDefined(); + const response = await op.promise; + const startTime = (2 * 10); + expect(response.uri).toBe(uri(startTime + '.' + (startTime + 10))); + expect(fetchDispatcher).toHaveBeenCalledTimes(3); + }); + + it('all prefetched segments, if all before given time', () => { + segmentPrefetch.prefetchSegmentsByTime(references[0].startTime); + segmentPrefetch.evict(40); + for (let i = 0; i < 3; i++) { + const op = segmentPrefetch.getPrefetchedSegment(references[i]); + expect(op).toBeNull(); + } + expect(fetchDispatcher).toHaveBeenCalledTimes(3); + }); + }); + describe('switchStream', () => { it('clears all prefetched segments', () => { - segmentPrefetch.prefetchSegments(references[0]); + segmentPrefetch.prefetchSegmentsByTime(references[0].startTime); segmentPrefetch.switchStream(createStream()); for (let i = 0; i < 3; i++) { const op = segmentPrefetch.getPrefetchedSegment(references[i]); @@ -127,7 +216,7 @@ describe('SegmentPrefetch', () => { }); it('do nothing if its same stream', async () => { - segmentPrefetch.prefetchSegments(references[0]); + segmentPrefetch.prefetchSegmentsByTime(references[0].startTime); segmentPrefetch.switchStream(stream); await expectSegmentsPrefetched(0); }); @@ -135,23 +224,23 @@ describe('SegmentPrefetch', () => { describe('resetLimit', () => { it('do nothing if the new limit is larger', async () => { - segmentPrefetch.prefetchSegments(references[0]); + segmentPrefetch.prefetchSegmentsByTime(references[0].startTime); segmentPrefetch.resetLimit(4); await expectSegmentsPrefetched(0); }); it('do nothing if the new limit is the same', async () => { - segmentPrefetch.prefetchSegments(references[0]); + segmentPrefetch.prefetchSegmentsByTime(references[0].startTime); segmentPrefetch.resetLimit(3); await expectSegmentsPrefetched(0); }); it('clears all prefetched segments beyond new limit', async () => { - segmentPrefetch.prefetchSegments(references[0]); + segmentPrefetch.prefetchSegmentsByTime(references[0].startTime); segmentPrefetch.resetLimit(1); // expecting prefetched reference 0 is kept - expectSegmentsPrefetched(0, 1); - // expecting prefetched references 1 and 2 are removd + await expectSegmentsPrefetched(0, 1); + // expecting prefetched references 1 and 2 are removed for (let i = 1; i < 3; i++) { const op = segmentPrefetch.getPrefetchedSegment(references[i]); expect(op).toBeNull(); @@ -160,7 +249,7 @@ describe('SegmentPrefetch', () => { // clear all to test the new limit by re-fetching. segmentPrefetch.clearAll(); // prefetch again. - segmentPrefetch.prefetchSegments(references[0]); + segmentPrefetch.prefetchSegmentsByTime(references[0].startTime); // expect only one is prefetched await expectSegmentsPrefetched(0, 1); // only dispatched fetch one more time. diff --git a/test/media/streaming_engine_unit.js b/test/media/streaming_engine_unit.js index 993bee5ddf..cf266c18a9 100644 --- a/test/media/streaming_engine_unit.js +++ b/test/media/streaming_engine_unit.js @@ -112,7 +112,8 @@ describe('StreamingEngine', () => { * @param {shaka.extern.aesKey=} aesKey The AES-128 key to put in * the manifest, if one should exist */ - function setupVod(trickMode, mediaOffset, aesKey) { + function setupVod(trickMode, mediaOffset, aesKey, + secondaryAudioVariant = false) { // For VOD, we fake a presentation that has 2 Periods of equal duration // (20 seconds), where each Period has 1 Variant and 1 text stream. // @@ -219,7 +220,8 @@ describe('StreamingEngine', () => { /* firstPeriodStartTime= */ 0, /* secondPeriodStartTime= */ 20, /* presentationDuration= */ 40, - aesKey); + aesKey, + secondaryAudioVariant); } function setupLive() { @@ -374,7 +376,7 @@ describe('StreamingEngine', () => { */ function setupManifest( firstPeriodStartTime, secondPeriodStartTime, presentationDuration, - aesKey) { + aesKey, secondaryAudioVariant = false) { const segmentDurations = { audio: segmentData[ContentType.AUDIO].segmentDuration, video: segmentData[ContentType.VIDEO].segmentDuration, @@ -397,7 +399,7 @@ describe('StreamingEngine', () => { /** @type {!shaka.media.PresentationTimeline} */(timeline), [firstPeriodStartTime, secondPeriodStartTime], presentationDuration, segmentDurations, initSegmentRanges, - timestampOffsets, aesKey); + timestampOffsets, aesKey, secondaryAudioVariant); audioStream = manifest.variants[0].audio; videoStream = manifest.variants[0].video; @@ -3937,31 +3939,80 @@ describe('StreamingEngine', () => { }); }); - describe('prefetch segments', () => { + /** + * Expect no buffer has been added to MSE. + */ + function expectNoBuffer() { + expect(mediaSourceEngine.initSegments).toEqual({ + audio: [false, false], + video: [false, false], + text: [], + }); + expect(mediaSourceEngine.segments).toEqual({ + audio: [false, false, false, false], + video: [false, false, false, false], + text: [false, false, false, false], + }); + } + + /** + * Expect buffers have been added to MSE. + */ + function expectHasBuffer(secondaryAudioVariant = false) { + expect(mediaSourceEngine.initSegments).toEqual({ + audio: [false, true], + video: [false, true], + text: [], + }); + expect(mediaSourceEngine.segments).toEqual({ + audio: [true, true, true, true], + video: [true, true, true, true], + text: [false, false, false, false], + }); + } + + /** + * @param {?boolean} hasRequest + */ + function expectSegmentRequest(hasRequest) { const segmentType = shaka.net.NetworkingEngine.RequestType.SEGMENT; + const context = { + type: shaka.net.NetworkingEngine.AdvancedRequestType.MEDIA_SEGMENT, + }; - let OriginalSegmentPrefetch; + const requests = [ + '0_audio_0', '0_video_0', '0_audio_1', + '0_video_1', '1_audio_2', '1_video_2', + '1_audio_3', '1_video_3', + ]; + + for (const request of requests) { + if (hasRequest) { + netEngine.expectRequest(request, segmentType, context); + } else { + netEngine.expectNoRequest(request, segmentType, context); + } + } + } + describe('prefetch segments', () => { beforeEach(() => { - OriginalSegmentPrefetch = shaka.media.SegmentPrefetch; - // eslint-disable-next-line no-restricted-syntax - shaka.media.SegmentPrefetch = function(config, stream) { - const fake = new shaka.test.FakeSegmentPrefetch(stream, segmentData); - return /** @type {?} */(fake); - }; - + shaka.media.SegmentPrefetch = Util.spyFunc( + jasmine.createSpy('SegmentPrefetch') + // eslint-disable-next-line + .and.callFake(function(prefetchLimit, stream) { + return new shaka.test.FakeSegmentPrefetch(prefetchLimit, + stream, segmentData); + }), + ); setupVod(); mediaSourceEngine = new shaka.test.FakeMediaSourceEngine(segmentData); createStreamingEngine(); const config = shaka.util.PlayerConfiguration.createDefault().streaming; - config.segmentPrefetchLimit = 3; + config.segmentPrefetchLimit = 5; streamingEngine.configure(config); }); - afterEach(() => { - shaka.media.SegmentPrefetch = OriginalSegmentPrefetch; - }); - it('should use prefetched segment without fetching again', async () => { streamingEngine.switchVariant(variant); await streamingEngine.start(); @@ -4023,61 +4074,186 @@ describe('StreamingEngine', () => { expectHasBuffer(); expectSegmentRequest(true); }); + }); - /** - * Expect no buffer has been added to MSE. - */ - function expectNoBuffer() { - expect(mediaSourceEngine.initSegments).toEqual({ - audio: [false, false], - video: [false, false], - text: [], - }); - expect(mediaSourceEngine.segments).toEqual({ - audio: [false, false, false, false], - video: [false, false, false, false], - text: [false, false, false, false], - }); - } + describe('prefetch audio variant segments', () => { + let altVariant; + let segmentPrefetchesCreated; - /** - * Expect buffers have been added to MSE. - */ - function expectHasBuffer() { - expect(mediaSourceEngine.initSegments).toEqual({ - audio: [false, true], - video: [false, true], - text: [], - }); - expect(mediaSourceEngine.segments).toEqual({ - audio: [true, true, true, true], - video: [true, true, true, true], - text: [false, false, false, false], - }); - } + beforeEach(() => { + segmentPrefetchesCreated = 0; + shaka.media.SegmentPrefetch = Util.spyFunc( + jasmine.createSpy('SegmentPrefetch') + // eslint-disable-next-line + .and.callFake(function(prefetchLimit, stream) { + segmentPrefetchesCreated++; + return new shaka.test.FakeSegmentPrefetch(prefetchLimit, + stream, segmentData); + }), + ); + setupVod(undefined, undefined, undefined, true); + altVariant = manifest.variants[1]; + mediaSourceEngine = new shaka.test.FakeMediaSourceEngine(segmentData); + createStreamingEngine(); + const config = shaka.util.PlayerConfiguration.createDefault().streaming; + config.segmentPrefetchLimit = 5; + config.prefetchAudioLanguages = ['und']; + streamingEngine.configure(config); + }); - /** - * @param {?boolean} hasRequest - */ - function expectSegmentRequest(hasRequest) { - const requests = [ - '0_audio_0', '0_video_0', '0_audio_1', - '0_video_1', '1_audio_2', '1_video_2', - '1_audio_3', '1_video_3', - ]; + it('should prefetch all audio variants for the language', async () => { + const segmentType = shaka.net.NetworkingEngine.RequestType.SEGMENT; + const context = { + type: shaka.net.NetworkingEngine.AdvancedRequestType.MEDIA_SEGMENT, + }; + + expect(segmentPrefetchesCreated).toBe(2); + + streamingEngine.switchVariant(variant); + await streamingEngine.start(); + playing = true; + expectNoBuffer(); + await runTest(); + + streamingEngine.switchVariant(altVariant); + await runTest(); + + expectHasBuffer(); + expectSegmentRequest(false); + netEngine.expectNoRequest('alt_11_audio_0', segmentType, context); + netEngine.expectNoRequest('alt_11_audio_1', segmentType, context); + expect(segmentPrefetchesCreated).toBe(3); + }); + + it('should not prefetch video if disabled', async () => { + const segmentType = shaka.net.NetworkingEngine.RequestType.SEGMENT; const context = { type: shaka.net.NetworkingEngine.AdvancedRequestType.MEDIA_SEGMENT, }; - for (const request of requests) { - if (hasRequest) { - netEngine.expectRequest(request, segmentType, context); - } else { - netEngine.expectNoRequest(request, segmentType, context); - } - } - } + const config = shaka.util.PlayerConfiguration.createDefault().streaming; + config.segmentPrefetchLimit = 5; + config.prefetchAudioLanguages = ['und']; + config.disableVideoPrefetch = true; + streamingEngine.configure(config); + + expect(segmentPrefetchesCreated).toBe(2); + + streamingEngine.switchVariant(variant); + await streamingEngine.start(); + playing = true; + expectNoBuffer(); + + await runTest(); + + streamingEngine.switchVariant(altVariant); + await runTest(); + + expectHasBuffer(); + netEngine.expectNoRequest('alt_11_audio_0', segmentType, context); + netEngine.expectNoRequest('alt_11_audio_1', segmentType, context); + netEngine.expectRequest('0_video_0', segmentType, context); + netEngine.expectRequest('0_video_1', segmentType, context); + netEngine.expectRequest('1_video_2', segmentType, context); + netEngine.expectRequest('1_video_3', segmentType, context); + expect(segmentPrefetchesCreated).toBe(2); + }); + + it('should use prefetched segment without fetching again', async () => { + streamingEngine.switchVariant(variant); + await streamingEngine.start(); + playing = true; + expectNoBuffer(); + + await runTest(); + + expectHasBuffer(); + expectSegmentRequest(false); + }); + + it('should re-use prefetch segment when force clear buffer', async () => { + streamingEngine.switchVariant(variant); + await streamingEngine.start(); + + playing = true; + expectNoBuffer(); + await runTest(); + expectHasBuffer(); + expectSegmentRequest(false); + + streamingEngine.switchVariant(altVariant, true, 0, true); + presentationTimeInSeconds = 0; + await runTest(); + expectHasBuffer(); + expectSegmentRequest(false); + + streamingEngine.switchVariant(variant, true, 0, true); + presentationTimeInSeconds = 0; + await runTest(); + expectHasBuffer(); + expectSegmentRequest(false); + }); + + it('should disable prefetch if limit is reset in middle', async () => { + streamingEngine.switchVariant(variant); + await streamingEngine.start(); + + playing = true; + expectNoBuffer(); + await runTest(); + expectHasBuffer(); + expectSegmentRequest(false); + + const config = shaka.util.PlayerConfiguration.createDefault().streaming; + config.segmentPrefetchLimit = 0; + streamingEngine.configure(config); + streamingEngine.switchVariant(variant, true, 0, true); + presentationTimeInSeconds = 0; + await runTest(); + expectHasBuffer(); + expectSegmentRequest(true); + }); + + it('should disable prefetch when limit is reset at begining', async () => { + const config = shaka.util.PlayerConfiguration.createDefault().streaming; + config.segmentPrefetchLimit = 0; + streamingEngine.configure(config); + streamingEngine.switchVariant(variant); + await streamingEngine.start(); + playing = true; + expectNoBuffer(); + await runTest(); + expectHasBuffer(); + expectSegmentRequest(true); + }); + + it('should switch to regular prefetch if config is reset in middle', + /** @suppress {accessControls} */ + async () => { + expect(segmentPrefetchesCreated).toBe(2); + + streamingEngine.switchVariant(variant); + await streamingEngine.start(); + + playing = true; + expectNoBuffer(); + await runTest(); + expectHasBuffer(); + expectSegmentRequest(false); + + const config = + shaka.util.PlayerConfiguration.createDefault().streaming; + config.segmentPrefetchLimit = 5; + config.prefetchAudioLanguages = []; + streamingEngine.configure(config); + streamingEngine.switchVariant(variant, true, 0, true); + presentationTimeInSeconds = 0; + await runTest(); + expectHasBuffer(); + expectSegmentRequest(false); + expect(streamingEngine.audioPrefetchMap_.size).toBe(0); + }); }); /** diff --git a/test/test/util/fake_segment_prefetch.js b/test/test/util/fake_segment_prefetch.js index 53324db17b..10788c9013 100644 --- a/test/test/util/fake_segment_prefetch.js +++ b/test/test/util/fake_segment_prefetch.js @@ -13,8 +13,16 @@ * @extends {shaka.media.SegmentPrefetch} */ shaka.test.FakeSegmentPrefetch = class { - constructor(stream, segmentData) { - /** @private {(Set.)} */ + /** + * Suppress the JSC_PRIVATE_OVERRIDE error for overriding prefetchPosTime_ + * @suppress {visibility} + */ + constructor(prefetchLimit, stream, segmentData) { + /** @private {number} */ + this.prefetchLimit_ = prefetchLimit; + + /** @private {(Set.)} */ this.requestedReferences_ = new Set(); /** @private {shaka.extern.Stream} */ @@ -24,14 +32,40 @@ shaka.test.FakeSegmentPrefetch = class { * @private {!Object.} */ this.segmentData_ = segmentData; + + /** @private {Array} */ + this.evictions_ = []; + + /** @private {number} */ + this.prefetchPosTime_ = 0; + + /** @private {boolean} */ + this.deleteOnGet_ = true; + + /** @private {number} */ + this.segmentNum_ = 0; } /** @override */ - prefetchSegments(reference) { - if (!(reference instanceof shaka.media.SegmentReference)) { - return; + getLastKnownPosition() { + return this.prefetchPosTime_; + } + + /** @override */ + prefetchSegmentsByTime(currTime) { + const maxTime = Math.max(currTime, this.prefetchPosTime_); + const iterator = this.streamObj_.segmentIndex.getIteratorForTime(maxTime); + let reference = iterator.next().value; + while (this.segmentNum_ < this.prefetchLimit_ && reference != null) { + if (!this.requestedReferences_.has(reference)) { + if (reference instanceof shaka.media.SegmentReference) { + this.segmentNum_++; + } + this.requestedReferences_.add(reference); + } + this.prefetchPosTime_ = reference.startTime; + reference = iterator.next().value; } - this.requestedReferences_.add(reference); } /** @override */ @@ -49,16 +83,32 @@ shaka.test.FakeSegmentPrefetch = class { /** @override */ clearAll() { this.requestedReferences_.clear(); + this.segmentNum_ = 0; + this.prefetchPosTime_ = 0; + } + + /** @override */ + evict(time) { + this.evictions_.push(time); } /** @override */ + deleteOnGet(newDeleteOnGet) { + this.deleteOnGet_ = newDeleteOnGet; + } + + /** + * @override + * @param {shaka.media.InitSegmentReference| + * shaka.media.SegmentReference} reference + * */ getPrefetchedSegment(reference) { if (!(reference instanceof shaka.media.SegmentReference)) { return null; } /** * The unit tests assume a segment is already prefetched - * if it was ever passed to prefetchSegments() as param. + * if it was ever passed to prefetchSegmentsByTime() as param. * Otherwise return null so the streaming engine being tested * will do actual fetch. */ @@ -78,7 +128,4 @@ shaka.test.FakeSegmentPrefetch = class { } return null; } - - /** @override */ - prefetchInitSegment(reference) {} }; diff --git a/test/test/util/streaming_engine_util.js b/test/test/util/streaming_engine_util.js index 776c0bf913..ae63df2a24 100644 --- a/test/test/util/streaming_engine_util.js +++ b/test/test/util/streaming_engine_util.js @@ -33,7 +33,11 @@ shaka.test.StreamingEngineUtil = class { expect(request.uris.length).toBe(1); const parts = request.uris[0].split('_'); - expect(parts.length).toBeGreaterThanOrEqual(3); + if (parts[3] === 'secondaryAudioVariant') { + expect(parts.length).toBe(4); + } else { + expect(parts.length).toBeGreaterThanOrEqual(3); + } const periodIndex = Number(parts[0]); expect(periodIndex).not.toBeNaN(); @@ -151,11 +155,13 @@ shaka.test.StreamingEngineUtil = class { * for each type of segment * @param {shaka.extern.aesKey=} aesKey The AES-128 key to provide * to streams, if desired. + * @param {boolean} [secondaryAudioVariant] * @return {shaka.extern.Manifest} */ static createManifest( presentationTimeline, periodStartTimes, presentationDuration, - segmentDurations, initSegmentRanges, timestampOffsets, aesKey) { + segmentDurations, initSegmentRanges, timestampOffsets, aesKey, + secondaryAudioVariant = false) { const Util = shaka.test.Util; /** @@ -197,12 +203,14 @@ shaka.test.StreamingEngineUtil = class { return position; }; + const getMap = new Map(); + /** * @param {string} type * @param {number} position * @return {shaka.media.SegmentReference} A SegmentReference. */ - const get = (type, position) => { + const get = (type, position, secondaryAudioVariant = false) => { // Note that we don't just directly compute the segment position because // a period start time could be in the middle of the previous period's // last segment. @@ -234,7 +242,8 @@ shaka.test.StreamingEngineUtil = class { const periodIndex = i; // 0-based const positionWithinPeriod = position - periodFirstPosition; - const initSegmentUri = periodIndex + '_' + type + '_init'; + const initSegmentUri = periodIndex + '_' + type + '_init' + + (secondaryAudioVariant ? '_secondaryAudioVariant' : ''); // The type can be 'text', 'audio', 'video', or 'trickvideo', // but we pull video init segment metadata from the 'video' part of the @@ -250,28 +259,41 @@ shaka.test.StreamingEngineUtil = class { } const d = segmentDurations[type]; - const getUris = () => [periodIndex + '_' + type + '_' + position]; + const getUris = () => [periodIndex + '_' + type + '_' + position + + (secondaryAudioVariant ? '_secondaryAudioVariant' : '')]; const periodStart = periodStartTimes[periodIndex]; const timestampOffset = (timestampOffsets && timestampOffsets[type]) || 0; const appendWindowStart = periodStartTimes[periodIndex]; const appendWindowEnd = periodIndex == periodStartTimes.length - 1? presentationDuration : periodStartTimes[periodIndex + 1]; - const ref = new shaka.media.SegmentReference( - /* startTime= */ periodStart + positionWithinPeriod * d, - /* endTime= */ periodStart + (positionWithinPeriod + 1) * d, - getUris, - /* startByte= */ 0, - /* endByte= */ null, - initSegmentReference, - timestampOffset, - appendWindowStart, - appendWindowEnd); - const ContentType = shaka.util.ManifestParserUtils.ContentType; - if (aesKey && - (type == ContentType.AUDIO || type == ContentType.VIDEO)) { - ref.aesKey = aesKey; + const refKey = [periodStart, + getUris()[0], + timestampOffset, + appendWindowStart, + appendWindowEnd].join(); + + let ref = getMap.get(refKey); + + if (!ref) { + ref = new shaka.media.SegmentReference( + /* startTime= */ periodStart + positionWithinPeriod * d, + /* endTime= */ periodStart + (positionWithinPeriod + 1) * d, + getUris, + /* startByte= */ 0, + /* endByte= */ null, + initSegmentReference, + timestampOffset, + appendWindowStart, + appendWindowEnd); + const ContentType = shaka.util.ManifestParserUtils.ContentType; + if (aesKey && + (type == ContentType.AUDIO || type == ContentType.VIDEO)) { + ref.aesKey = aesKey; + } + getMap.set(refKey, ref); } + return ref; }; @@ -302,15 +324,51 @@ shaka.test.StreamingEngineUtil = class { primary: false, decodingInfos: [], }; + let variant2; + + if (secondaryAudioVariant) { + variant2 = { + video: null, + audio: null, + allowedByApplication: true, + allowedByKeySystem: true, + bandwidth: 0, + id: 10, + language: 'und', + primary: false, + decodingInfos: [], + }; + } if ('video' in segmentDurations) { variant.video = /** @type {shaka.extern.Stream} */( shaka.test.StreamingEngineUtil.createMockStream('video', 0)); + + if (secondaryAudioVariant) { + variant2.video = variant.video; + } } if ('audio' in segmentDurations) { variant.audio = /** @type {shaka.extern.Stream} */( shaka.test.StreamingEngineUtil.createMockStream('audio', 1)); + if (secondaryAudioVariant) { + variant2.audio = /** @type {shaka.extern.Stream} */( + shaka.test.StreamingEngineUtil.createMockStream('audio', 11)); + + const ContentType = shaka.util.ManifestParserUtils.ContentType; + const segmentIndex = new shaka.test.FakeSegmentIndex(); + segmentIndex.find.and.callFake((time) => find(ContentType.AUDIO, time)); + segmentIndex.get.and.callFake((pos) => + get(ContentType.AUDIO, pos, true)); + + const createSegmentIndexSpy = Util.funcSpy( + variant2.audio.createSegmentIndex); + createSegmentIndexSpy.and.callFake(() => { + variant2.audio.segmentIndex = segmentIndex; + return Promise.resolve(); + }); + } } /** @type {?shaka.extern.Stream} */ @@ -362,6 +420,10 @@ shaka.test.StreamingEngineUtil = class { } manifest.variants = [variant]; + if (secondaryAudioVariant) { + manifest.variants.push(variant2); + } + return manifest; } From 33b40cfcce6909f8d05c53753fdb22d7c6606b8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Velad=20Galv=C3=A1n?= Date: Mon, 29 Jan 2024 18:09:52 +0100 Subject: [PATCH 05/64] fix(CMCD): Fix CMCD for some mimetypes in src= (#6178) --- lib/util/cmcd_manager.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/util/cmcd_manager.js b/lib/util/cmcd_manager.js index d32ce72d18..a312570068 100644 --- a/lib/util/cmcd_manager.js +++ b/lib/util/cmcd_manager.js @@ -407,6 +407,15 @@ shaka.util.CmcdManager = class { */ getObjectTypeFromMimeType_(mimeType) { switch (mimeType.toLowerCase()) { + case 'audio/mp4': + case 'audio/webm': + case 'audio/ogg': + case 'audio/mpeg': + case 'audio/aac': + case 'audio/flac': + case 'audio/wav': + return shaka.util.CmcdManager.ObjectType.AUDIO; + case 'video/webm': case 'video/mp4': case 'video/mpeg': @@ -417,6 +426,7 @@ shaka.util.CmcdManager = class { case 'application/vnd.apple.mpegurl': case 'application/dash+xml': case 'video/vnd.mpeg.dash.mpd': + case 'application/vnd.ms-sstr+xml': return shaka.util.CmcdManager.ObjectType.MANIFEST; default: From 5b141eb76ac5bfb8300cdf42489ca68f7cb5bfe9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Velad=20Galv=C3=A1n?= Date: Mon, 29 Jan 2024 18:39:34 +0100 Subject: [PATCH 06/64] fix(Ads): Fix initial ads configuration (#6176) Related to https://github.com/shaka-project/shaka-player/issues/6169 --- lib/player.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/player.js b/lib/player.js index 49bb6fb05d..31ecaeefa1 100644 --- a/lib/player.js +++ b/lib/player.js @@ -723,6 +723,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget { if (shaka.Player.adManagerFactory_) { this.adManager_ = shaka.Player.adManagerFactory_(); + this.adManager_.configure(this.config_.ads); } // If the browser comes back online after being offline, then try to play From 8a9f17d48bef85a184d63648d47b86cc5c175375 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Velad=20Galv=C3=A1n?= Date: Mon, 29 Jan 2024 18:57:26 +0100 Subject: [PATCH 07/64] feat(CMCD): Add support to dl, nrr and nor parameters (#6171) --- lib/util/cmcd_manager.js | 95 +++++++++++++++++++++++++++++++++- test/util/cmcd_manager_unit.js | 10 ++-- 2 files changed, 99 insertions(+), 6 deletions(-) diff --git a/lib/util/cmcd_manager.js b/lib/util/cmcd_manager.js index a312570068..ad71ea5fa4 100644 --- a/lib/util/cmcd_manager.js +++ b/lib/util/cmcd_manager.js @@ -9,6 +9,7 @@ goog.provide('shaka.util.CmcdManager'); goog.require('goog.Uri'); goog.require('shaka.log'); goog.require('shaka.net.NetworkingEngine'); +goog.require('shaka.util.ArrayUtils'); /** * @summary @@ -193,11 +194,45 @@ shaka.util.CmcdManager = class { if (stream) { if (isMedia) { data.bl = this.getBufferLength_(stream.type); + if (data.ot !== ObjectType.TIMED_TEXT) { + const remainingBufferLength = + this.getRemainingBufferLength_(stream.type); + const playbackRate = this.playerInterface_.getPlaybackRate(); + if (playbackRate) { + data.dl = remainingBufferLength / Math.abs(playbackRate); + } else { + data.dl = remainingBufferLength; + } + } } if (stream.bandwidth) { data.br = stream.bandwidth / 1000; } + + if (stream.segmentIndex && segment) { + const iterator = stream.segmentIndex.getIteratorForTime( + segment.endTime, /* allowNonIndepedent= */ true); + if (iterator) { + const nextSegment = iterator.next().value; + if (nextSegment && nextSegment != segment) { + if (!shaka.util.ArrayUtils.equal( + segment.getUris(), nextSegment.getUris())) { + data.nor = this.urlToRelativePath_( + nextSegment.getUris()[0], request.uris[0]); + } + if ((nextSegment.startByte || nextSegment.endByte) && + (segment.startByte != nextSegment.startByte || + segment.endByte != nextSegment.endByte)) { + let range = nextSegment.startByte + '-'; + if (nextSegment.endByte) { + range += nextSegment.endByte; + } + data.nrr = range; + } + } + } + } } if (isMedia && data.ot !== ObjectType.TIMED_TEXT) { @@ -335,7 +370,7 @@ shaka.util.CmcdManager = class { data.su = this.buffering_; } - // TODO: Implement rtp, nrr, nor, dl + // TODO: Implement rtp if (useHeaders) { const headers = shaka.util.CmcdManager.toHeaders(data); @@ -458,6 +493,64 @@ shaka.util.CmcdManager = class { return (range.end - start) * 1000; } + /** + * Get the remaining buffer length for a media type in milliseconds + * + * @param {string} type + * @return {number} + * @private + */ + getRemainingBufferLength_(type) { + const ranges = this.playerInterface_.getBufferedInfo()[type]; + + if (!ranges.length) { + return 0; + } + + const start = this.playerInterface_.getCurrentTime(); + const range = ranges.find((r) => r.start <= start && r.end >= start); + + if (!range) { + return 0; + } + + return (range.end - start) * 1000; + } + + /** + * Constructs a relative path from a URL + * + * @param {string} url + * @param {string} base + * @return {string} + * @private + */ + urlToRelativePath_(url, base) { + const to = new URL(url); + const from = new URL(base); + + if (to.origin !== from.origin) { + return url; + } + + const toPath = to.pathname.split('/').slice(1); + const fromPath = from.pathname.split('/').slice(1, -1); + + // remove common parents + while (toPath[0] === fromPath[0]) { + toPath.shift(); + fromPath.shift(); + } + + // add back paths + while (fromPath.length) { + fromPath.shift(); + toPath.unshift('..'); + } + + return toPath.join('/'); + } + /** * Get the stream format * diff --git a/test/util/cmcd_manager_unit.js b/test/util/cmcd_manager_unit.js index 704355a57d..cdf53a8e30 100644 --- a/test/util/cmcd_manager_unit.js +++ b/test/util/cmcd_manager_unit.js @@ -209,10 +209,10 @@ describe('CmcdManager', () => { it('modifies segment request uris', () => { const r = ObjectUtils.cloneObject(request); cmcdManager.applySegmentData(r, segmentInfo); - const uri = 'https://test.com/test.mpd?CMCD=bl%3D21200%2Cbr%3D5234%2Ccid%3D%22' + - 'testing%22%2Cd%3D3330%2Cmtp%3D10000%2Cot%3Dv%2Csf%3Dd%2C' + - 'sid%3D%222ed2d1cd-970b-48f2-bfb3-50a79e87cfa3%22%2Cst%3Dv%2Csu%2C' + - 'tb%3D4000'; + const uri = 'https://test.com/test.mpd?CMCD=bl%3D21200%2Cbr%3D5234%' + + '2Ccid%3D%22testing%22%2Cd%3D3330%2Cdl%3D21200%2Cmtp%3D10000%2Cot%' + + '3Dv%2Csf%3Dd%2Csid%3D%222ed2d1cd-970b-48f2-bfb3-50a79e87cfa3%22%2' + + 'Cst%3Dv%2Csu%2Ctb%3D4000'; expect(r.uris[0]).toBe(uri); }); @@ -250,7 +250,7 @@ describe('CmcdManager', () => { expect(r.headers).toEqual({ 'testing': '1234', 'CMCD-Object': 'br=5234,d=3330,ot=v,tb=4000', - 'CMCD-Request': 'bl=21200,mtp=10000,su', + 'CMCD-Request': 'bl=21200,dl=21200,mtp=10000,su', 'CMCD-Session': 'cid="testing",sf=d,' + 'sid="2ed2d1cd-970b-48f2-bfb3-50a79e87cfa3",st=v', }); From 3537dc0a68eeb22890ffc7e658e5eb940eb1fd43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Velad=20Galv=C3=A1n?= Date: Tue, 30 Jan 2024 08:53:46 +0100 Subject: [PATCH 08/64] fix(CMCD): Allow reconfigure session ID (#6177) --- lib/util/cmcd_manager.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/util/cmcd_manager.js b/lib/util/cmcd_manager.js index ad71ea5fa4..05f75af699 100644 --- a/lib/util/cmcd_manager.js +++ b/lib/util/cmcd_manager.js @@ -66,6 +66,9 @@ shaka.util.CmcdManager = class { */ configure(config) { this.config_ = config; + if (this.config_.sessionId && this.config_.sessionId != this.sid_) { + this.sid_ = ''; + } } /** From 8c93425b2e3b709a071bdd7351e96a0984bb8396 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Velad=20Galv=C3=A1n?= Date: Tue, 30 Jan 2024 13:11:15 +0100 Subject: [PATCH 09/64] docs: Update roadmap for 5.0 (#6183) --- roadmap.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/roadmap.md b/roadmap.md index 556deca865..01c8c23493 100644 --- a/roadmap.md +++ b/roadmap.md @@ -22,6 +22,9 @@ Candidate features for future release cycles: v5.0 - 2024 Q1 - Preload API https://github.com/shaka-project/shaka-player/issues/880 + - AES-256 and AES-256-CTR (HLS) + https://github.com/shaka-project/shaka-player/issues/6001 + - Detect maximum HW resolution automatically on some platforms ===== From a3320707b9344a84242bcdc413f1bbf23bfa49e9 Mon Sep 17 00:00:00 2001 From: Iragne Date: Tue, 30 Jan 2024 15:57:02 +0100 Subject: [PATCH 10/64] fix(DASH): Update dash manifest when minimumUpdatePeriod = 0 (#6187) Fixes https://github.com/shaka-project/shaka-player/issues/6185 --- lib/dash/dash_parser.js | 2 +- test/dash/dash_parser_live_unit.js | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/lib/dash/dash_parser.js b/lib/dash/dash_parser.js index 1dc9398fce..70c712d950 100644 --- a/lib/dash/dash_parser.js +++ b/lib/dash/dash_parser.js @@ -1692,7 +1692,7 @@ shaka.dash.DashParser = class { // An attribute which is present and set to 0 should still result in // periodic updates. For more, see: // https://github.com/Dash-Industry-Forum/Guidelines-TimingModel/issues/48 - if (this.updatePeriod_ <= 0) { + if (this.updatePeriod_ < 0) { return; } diff --git a/test/dash/dash_parser_live_unit.js b/test/dash/dash_parser_live_unit.js index 90d78f0ef9..e26594f374 100644 --- a/test/dash/dash_parser_live_unit.js +++ b/test/dash/dash_parser_live_unit.js @@ -642,6 +642,25 @@ describe('DashParser Live', () => { expect(updateTick).toHaveBeenCalledTimes(1); }); + it('still updates when @minimumUpdatePeriod is zero', async () => { + const lines = [ + '', + ]; + // updateTime parameter sets @minimumUpdatePeriod in the manifest. + const manifestText = makeSimpleLiveManifestText(lines, /* updateTime= */ 0); + + /** @type {!jasmine.Spy} */ + const tickAfter = updateTickSpy(); + Date.now = () => 0; + + fakeNetEngine.setResponseText('dummy://foo', manifestText); + await parser.start('dummy://foo', playerInterface); + + expect(tickAfter).toHaveBeenCalledTimes(1); + const delay = tickAfter.calls.mostRecent().args[0]; + expect(delay).toBe(0); + }); + it('uses @minimumUpdatePeriod', async () => { const lines = [ '', From 60fd7fd09c14e192780690596f5e6f82cc5df408 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Velad=20Galv=C3=A1n?= Date: Tue, 30 Jan 2024 20:02:02 +0100 Subject: [PATCH 11/64] test: Fix some tests in Safari 17 (#6190) --- test/player_integration.js | 6 ++++++ .../text-displayer-native-basic-cue.png | Bin 4426 -> 4552 bytes .../text-displayer-native-line-alignment.png | Bin 5599 -> 4774 bytes 3 files changed, 6 insertions(+) diff --git a/test/player_integration.js b/test/player_integration.js index f918580f2f..3bd10843d4 100644 --- a/test/player_integration.js +++ b/test/player_integration.js @@ -1012,6 +1012,9 @@ describe('Player', () => { }); it('buffers ahead of the playhead', async () => { + if (window.ManagedMediaSource) { + pending('ManagedMediaSource has buffer control signals.'); + } player.configure('streaming.bufferingGoal', 10); await player.load('test:sintel_long_compiled'); @@ -1036,6 +1039,9 @@ describe('Player', () => { }); it('clears buffer behind playhead', async () => { + if (window.ManagedMediaSource) { + pending('ManagedMediaSource has buffer control signals.'); + } player.configure('streaming.bufferingGoal', 30); player.configure('streaming.bufferBehind', 30); diff --git a/test/test/assets/screenshots/safari-Mac/text-displayer-native-basic-cue.png b/test/test/assets/screenshots/safari-Mac/text-displayer-native-basic-cue.png index 4c6aca69c2e545b795b08a88128fad909a82e082..cc8069a6b3f79bf7d7cf3d0d7d08f284b3a0e6f8 100644 GIT binary patch literal 4552 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 ACIA2c literal 4426 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 H+D85dL=#HN diff --git a/test/test/assets/screenshots/safari-Mac/text-displayer-native-line-alignment.png b/test/test/assets/screenshots/safari-Mac/text-displayer-native-line-alignment.png index f2c7d19c0e38ed801b712daa10b14ab669abb3d1..beb6745e29f6cfc47677d5720f836f0bb8336139 100644 GIT binary patch literal 4774 zcmeHLi8qx0+a_DfAQFSIG(sfHU>L?$gfH3E#MljKC|gCynk`HACWEXKWiQ#+G4>f> z%9=2?WF4|^zvuV<7w>!CbDrlp_qosKoX`DS*XO>j`*~tajC5Hq@?E5(qhr9}{ zqt^uDFXx$o=feCB2OS-!hrYI!g&+M|+l9taOy~xUvV9zUwmnTIJ48A2a9k17{3*+1 zsPNz?6Vp`_M(w1ZCZ?B$Aj1%)s{Zd6hOv>0-``=J`p^Wg9;U0~AZJ9B&y3XB$zDLw zos6E9zDae6-QGd-v`fnYZ&Y-2RG50uOA#nlxDw8691q0UxdfG z`752^R&d;GIdy-9cRo1TX9mv@6?mJmTRc3}TfHE^Qrp2b#!R~1eqWhQ*4Nt}L;^$X z<2t|$k<;?_akCwGpVh^EhOQ@MMC%NsWv&&0mj};3UGOBD%Oxw)FAI8wIfEcWo#zVr zbR4w%CLpDmTM?qNBle(Rfi63W@LBkl>K!X3o(k-TqTu9uEeZF2sExR0y#*?6?9ht; zU=b$fQXzK=XFiC4F&p-4GOCU)^lV5Cue3@!Ugciq<6ef55j9Q!8Z{Tj#qbh^#9X?+ zrH=33RV5<|u&4q9FoTB>SGQuC?8sm-BwZrS0ELxEk5yjUHvsNnAWZEQRW~X|=bGxVI@g4{fDjsYJGKxibYGIki(IJ-e$8dT)LzjqSm+(&SggsV zv&x}!t&7)Y5og$$%aMgM;Xq>zpyRzA7zV^JC-0L?y{XI+$tT=HYG+aT+-n-v?C7EA8q}a zl(|wZw|gVa01sORu?hKHmuWh^=~xLCO6%j<-^wfBn!LsD=H@{HcTC?wezc#~5_$Ca z7h9x;0o=~Mr&Hw0^7PCib1zmb($&k56D64)+MiF-l>> zwfl=xa_g%izm2xUD5e`ZaKT*WwfYfG^sLX+P}L5KWW?@`C6SUNQCYC_MwMR14OfwW z>drfXOu4*>V?94#?F1o@stI+ALgiw1-L%15i77@HS<+y&wG7{%`r#fcgJ&4lua?jL zuK(g$f;>~)L3&S`gQi@A^KRt9Y;-o(gY?CR!E>mi(}2crUaUXT6bq8wUc&ztl@;-u zat)bGhqvYMg>?)P0yKcESS)lmIuGV_H-R8&eh(ovY%-dqu6D>lq$=}pL}KcHz)j38 zbuEkDzl*1N#mW6$|2Hw4wdq2BG)K7Z_TVk!L14W%*zCb@ye(@`bl1)E9dGOZyiAU{ zuGX+qWFc*CH>qi3$-uIz`W{I4I^gQxzkI3q_nKh&2UKjW!>^3GneTNG4iR$cwyaIX zrDge$^n;3Soxf}2i4EmvVkzv1baZofXvbNoYFSgxP1h++k9!P-W=S|g|6+Yz-`J0l z_6+HUEJ}iEq;*+sO3Ym1HSTI;;7ZEsT?{=h5HEX3k6qray6!a5E{@mfyX za7pUbz_s^BynD-cKK5HwZjC?P?hHtO`%y1M&R3F4V4Gmmc0fRD*Ssw(E=;QC$?9by z*mg4!$b}-4MzAEuk>qN>wX6rSqzc_ii}?iXy6bUhRFXc%?=LRu_h_{caCG|BTsipR z}BFPxW|-Ur3K?sbmuuE<;Rlj$X80L&*8M!)=QNx9gnRhCsDh`N*oi>|0OZ2 z$Ftqk+<%4^@W_3fY-xw1eEMWZ0^g}aJ5t-aHrEe-^rMjBP6^1^^6BFnKhn|w?NZUn z&BrH36P&t#VUnb0Av0sQK)JciEE}H#-uPW6nCFg>=QILSh0i~F{AB+4CS{S|_$OuG zG%Cr6`MbprPck(H@r0ZNFrpxMG~1z2ibw)vXDz?CO^DHVPp`AiWfFb`tNm~ z`gwd4ek7z6_u#?VdqB4wei)zf+zj44AC-tm*1fMrTwN&|ZuDV^iDeWTX=+Y?NEmP$ z*;$fXF9;UK>3N@i-^O_jxx3s#Bs#eoe}JR|ps1I?Y&zTW#VfYPgBOpnv-Wfc>cM@??Lt~8s z5aQfb^ouU2bc359!x5Xy=q`kE_DA>U=?pBAeIoH%4j<{ee~#0ll4G?)1OH9e{@xjbK7xcigdC_*_gQ>m`rwq8D z6Mv9Ujf}?Wh>V_?+3MI1eN)38X4e0K_hIVt&*wjyR+XF?lipOoN!D09*WazPXax^= zwQ)}3S2?p7t^jbsCq})DiV=IM1}1v<@n&2uL!`NM#sx?E9mS^oiR2^H%h5EDfHFSd z$tknyi?!?CY_1^d%$kZ)w@YgRrC+|lhfO90Jc(4fl24CuUcHb6uu{zXUMsv07?efT z!cRADU#vvoO7B_gi4Udr>O5clNgCL*?K?1+aUtU}Hs|cr`*eTYA5HnFS3wKkyOD{E zADHBY+iN&#;de5BIZP(3xldQd0}}2S-)Ut)a4!p&nQDl*WZV$3O(0WWXJm_*nufN$ zEi*L9DxM`Be5-JqJOX3A5~l8}on60L98zMaxB@TDEe#T%d|z`pk^gbY(5`cE2D+E?MpFZAwk8(C36YbjW(-3mPt5AVwXe|=5UX%wclKt+G*F)D!L?95L_Nq z>$`~g?6)dSrGZJ{R}^66_%m5H^RFd)^%hxN*?()9u`-0`bk1Llf{eSW6#Qmc91S#_ z^LUUFZF8@=Q{-Fu{FsQ*e3Z;-hy|=CF__ib~S8PWCW>w;HzmHMBiW494E28ha5stRr(Y@e>frQ-WS(NoH<|HiZk=#h_0+nWUPZ(f`*!>fb+>l;i|jCgO^C zR`1RWbl2Km@ar3~-Pg^Pmt>i(toYr=zlKv1GKs%ASmeCNLciZ1_1-FwuU#(VuUl(g zh%nVw!I2QUiBFmyHm$S1x2o}J%flh}i3|#B?ggby@kXl86=5frT&o=yF1|Wl;TfCw z@|q`@CQqf&K^hPrz6SB|!%H#kwHM;RH9`!BAZLR)?&g|#`UJ%4bxCTvvraOA(s+g2 ztt%uWdt${2c+@ZT%S-p5PefYvtrH+w$d6m3qZmd`-D1W946psKx2 z=6fY}v8&HWnkz*}<%*H2muoA^Gs)FFa%)5!05rFB=DMru& zkLh$&fInT*m=27oWQijHFD7%c_yAxCTu<>V!!@Leu&cyA4L;*P{u_LD9_y6acTG1w zhv*}t-etXF>qL8PpuAG+b1<5t(J__yOW(W?E{$*n_D#r#+4S^U-b5TlxWz%>v97NU z)qw6DNx09v%TN63lL7NOc5dG8|K@*4FqU&zO#=N^eV5a6EYF?&Et+9ZsPk~TxvMp3 z*Fo3dN_q1MY(=RQgB@m(YM!x5KpZRAD7Ic-MO*bA%${S~QFqtn^ygbR2I{1^e`gpRfo!4&Wi&GJ8F`(S1 zkHKz!M^VOSUB9~4{tx8W)F#}nF+jpqKqHGGGM<`C5S*XaH?O1SeUb%B+o`kb;?&&j zKMJL`lR#B3a4~&R%FgBT+%=6uce{3>B(TcWSkbsp3uq6y=DFmsew>`|d=;SL6V(W6 zD2Di!;z?n>`3~uWB=N;|a`tG4CAhO_U7mq3R)Ratc$c7@F&DQEIJGW|#6dsH6(nC! z@%9HrTEIf(-VQ8$?05D|63L__8D9VG9GCl5%|L}$+?&lwiiXnERX4U&8BoelBRNrC zMJ+B01n$%~;E;3GXx|aYFWWtCW3@AzFcdHlxvT49B*QzB1{Uffa?!7V#U*zx$J+><3)z^!))_E z3E$p@$$K4Kj`EGUZH*g{Sv%*tZvf2NIZVSmmGfj^z=hcqTS(ICIue~m+_pag*5SA? z>Ua2BeEI&Q=60D2RSR+;5|_VG%g1R+U$yr?A-1Q$EYOVT zC|3fLn5WD^#=yS($we+XT*?J+81+WIO{$G!oo(=0D?ZLIQay7!UWaI%3PSAn{UQ@F zz-MWc^6AqA4cTK;QdkV{&=mDM`#+|pS3~a9n}qnPvBZ>w*yfkq;DPqmMOSb+$aYVY z=$Tna6`8XwydXB&$g>W5W)S$a6~O|=&%FS2?G=Tl$|kGax=Dj1pnh@|NNKfGp+MnM zn(A_B#>!ez?r+^^E$E2A+bC^qB!+{7ma3yoH0S2vFn;)dEU{z9L1(Ov8U^10{y)*_ M>lkU5-L?<=510lg>;M1& literal 5599 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 ChGA0x From 0d9efc2831a05f216fcfd0d8412daa3a062da85d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Velad=20Galv=C3=A1n?= Date: Tue, 30 Jan 2024 20:02:14 +0100 Subject: [PATCH 12/64] docs: Add Hisense information to README (#6186) --- README.md | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index fa22f3a165..cedf55a290 100644 --- a/README.md +++ b/README.md @@ -45,6 +45,7 @@ for the up-to-date list of maintained branches of Shaka Player. |Chromecast². | - | - | - | - | - | - | - | - |**Y**| |Tizen TV³ | - | - | - | - | - | - | - | - |**Y**| |WebOS⁶ | - | - | - | - | - | - | - | - |**Y**| +|Hisense⁷ | - | - | - | - | - | - | - | - |**Y**| |Xbox One | - | - | - | - | - | - | - | - |**Y**| |Playstation 4⁷| - | - | - | - | - | - | - | - |**Y**| |Playstation 5⁷| - | - | - | - | - | - | - | - |**Y**| @@ -168,18 +169,19 @@ MSS features **not** supported: ## DRM support matrix -|Browser |Widevine |PlayReady|FairPlay |ClearKey⁶ | -|:--------:|:--------:|:-------:|:-------:|:--------:| -|Chrome¹ |**Y** | - | - |**Y** | -|Firefox² |**Y** | - | - |**Y** | -|Edge³ | - |**Y** | - | - | -|Edge Chromium|**Y** |**Y** | - |**Y** | -|Safari | - | - |**Y** | - | -|Opera |untested⁵ | - | - |untested⁵ | -|Chromecast|**Y** |**Y** | - |untested⁵ | -|Tizen TV |**Y** |**Y** | - |untested⁵ | -|WebOS⁷ |untested⁷ |untested⁷| - |untested⁷ | -|Xbox One | - |**Y** | - | - | +|Browser |Widevine |PlayReady|FairPlay |ClearKey⁶ | +|:------------:|:--------:|:-------:|:-------:|:--------:| +|Chrome¹ |**Y** | - | - |**Y** | +|Firefox² |**Y** | - | - |**Y** | +|Edge³ | - |**Y** | - | - | +|Edge Chromium |**Y** |**Y** | - |**Y** | +|Safari | - | - |**Y** | - | +|Opera |untested⁵ | - | - |untested⁵ | +|Chromecast |**Y** |**Y** | - |untested⁵ | +|Tizen TV |**Y** |**Y** | - |untested⁵ | +|WebOS⁷ |untested⁷ |untested⁷| - |untested⁷ | +|Hisense⁷ |untested⁷ |untested⁷| - |untested⁷ | +|Xbox One | - |**Y** | - | - | |Playstation 4⁷| - |untested⁷| - |untested⁷ | |Playstation 5⁷| - |untested⁷| - |untested⁷ | From 038e894e82a5636dd7ca6661b34770201a894edf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Velad=20Galv=C3=A1n?= Date: Tue, 30 Jan 2024 20:02:30 +0100 Subject: [PATCH 13/64] feat(CMCD): Add support to rtp parameter (#6184) --- demo/config.js | 2 ++ externs/shaka/player.js | 6 +++++- lib/util/cmcd_manager.js | 35 ++++++++++++++++++++++++++++++-- lib/util/player_configuration.js | 1 + test/util/cmcd_manager_unit.js | 1 + 5 files changed, 42 insertions(+), 3 deletions(-) diff --git a/demo/config.js b/demo/config.js index d658ca023c..2a75a8e5da 100644 --- a/demo/config.js +++ b/demo/config.js @@ -311,6 +311,8 @@ shakaDemo.Config = class { .addBoolInput_('Enabled', 'cmcd.enabled') .addTextInput_('Session ID', 'cmcd.sessionId') .addTextInput_('Content ID', 'cmcd.contentId') + .addNumberInput_('RTP safety Factor', 'cmcd.rtpSafetyFactor', + /* canBeDecimal= */ true) .addBoolInput_('Use Headers', 'cmcd.useHeaders'); } diff --git a/externs/shaka/player.js b/externs/shaka/player.js index 30e74dacf6..a56b7f9e2f 100644 --- a/externs/shaka/player.js +++ b/externs/shaka/player.js @@ -1510,7 +1510,8 @@ shaka.extern.AdvancedAbrConfiguration; * enabled: boolean, * useHeaders: boolean, * sessionId: string, - * contentId: string + * contentId: string, + * rtpSafetyFactor: number * }} * * @description @@ -1533,6 +1534,9 @@ shaka.extern.AdvancedAbrConfiguration; * characters. This value is consistent across multiple different sessions and * devices and is defined and updated at the discretion of the service * provider. + * @property {number} rtpSafetyFactor + * RTP safety factor. + * Defaults to 5. * @exportDoc */ shaka.extern.CmcdConfiguration; diff --git a/lib/util/cmcd_manager.js b/lib/util/cmcd_manager.js index 05f75af699..8773832e3f 100644 --- a/lib/util/cmcd_manager.js +++ b/lib/util/cmcd_manager.js @@ -11,6 +11,8 @@ goog.require('shaka.log'); goog.require('shaka.net.NetworkingEngine'); goog.require('shaka.util.ArrayUtils'); +goog.requireType('shaka.media.SegmentReference'); + /** * @summary * A CmcdManager maintains CMCD state as well as a collection of utility @@ -235,6 +237,10 @@ shaka.util.CmcdManager = class { } } } + const rtp = this.calculateRtp_(stream, segment); + if (!isNaN(rtp)) { + data.rtp = rtp; + } } } @@ -373,8 +379,6 @@ shaka.util.CmcdManager = class { data.su = this.buffering_; } - // TODO: Implement rtp - if (useHeaders) { const headers = shaka.util.CmcdManager.toHeaders(data); if (!Object.keys(headers).length) { @@ -554,6 +558,33 @@ shaka.util.CmcdManager = class { return toPath.join('/'); } + /** + * Calculate requested maximun throughput + * + * @param {shaka.extern.Stream} stream + * @param {shaka.media.SegmentReference} segment + * @return {number} + * @private + */ + calculateRtp_(stream, segment) { + const playbackRate = this.playerInterface_.getPlaybackRate() || 1; + const currentBufferLevel = + this.getRemainingBufferLength_(stream.type) || 500; + const bandwidth = stream.bandwidth; + if (!bandwidth) { + return NaN; + } + const segmentDuration = segment.endTime - segment.startTime; + // Calculate file size in kilobits + const segmentSize = bandwidth * segmentDuration / 1000; + // Calculate time available to load file in seconds + const timeToLoad = (currentBufferLevel / playbackRate) / 1000; + // Calculate the exact bandwidth required + const minBandwidth = segmentSize / timeToLoad; + // Include a safety buffer + return minBandwidth * this.config_.rtpSafetyFactor; + } + /** * Get the stream format * diff --git a/lib/util/player_configuration.js b/lib/util/player_configuration.js index 2f4784bdf5..79b950e60c 100644 --- a/lib/util/player_configuration.js +++ b/lib/util/player_configuration.js @@ -322,6 +322,7 @@ shaka.util.PlayerConfiguration = class { enabled: false, sessionId: '', contentId: '', + rtpSafetyFactor: 5, useHeaders: false, }; diff --git a/test/util/cmcd_manager_unit.js b/test/util/cmcd_manager_unit.js index cdf53a8e30..dcd33b058b 100644 --- a/test/util/cmcd_manager_unit.js +++ b/test/util/cmcd_manager_unit.js @@ -125,6 +125,7 @@ describe('CmcdManager', () => { enabled: false, sessionId: '', contentId: 'testing', + rtpSafetyFactor: 5, useHeaders: false, }; From 47602c6f5eda7ad5c5768f418c3825c40bf4ddcf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Velad=20Galv=C3=A1n?= Date: Tue, 30 Jan 2024 20:02:44 +0100 Subject: [PATCH 14/64] feat!: Remove com.adobe.primetime keysystem (#6189) `com.adobe.primetime` is not implemented in any browser and no one has reported any problems in the 8 years of Shaka Player. --- demo/main.js | 1 - lib/media/drm_engine.js | 1 - lib/offline/storage.js | 3 +-- lib/util/player_configuration.js | 2 -- test/dash/dash_parser_content_protection_unit.js | 7 ------- 5 files changed, 1 insertion(+), 13 deletions(-) diff --git a/demo/main.js b/demo/main.js index be5f479815..eff5131121 100644 --- a/demo/main.js +++ b/demo/main.js @@ -1877,7 +1877,6 @@ shakaDemo.Main.commonDrmSystems = [ 'com.widevine.alpha', 'com.microsoft.playready', 'com.apple.fps', - 'com.adobe.primetime', 'org.w3.clearkey', ]; diff --git a/lib/media/drm_engine.js b/lib/media/drm_engine.js index b4f3cb5a1e..cbd49d7329 100644 --- a/lib/media/drm_engine.js +++ b/lib/media/drm_engine.js @@ -1831,7 +1831,6 @@ shaka.media.DrmEngine = class { 'com.microsoft.playready.recommendation', 'com.apple.fps.1_0', 'com.apple.fps', - 'com.adobe.primetime', ]; const basicVideoCapabilities = [ diff --git a/lib/offline/storage.js b/lib/offline/storage.js index 4f4e79afdd..a4abd259b1 100644 --- a/lib/offline/storage.js +++ b/lib/offline/storage.js @@ -1654,7 +1654,6 @@ shaka.offline.Storage.defaultSystemIds_ = new Map() .set('com.microsoft.playready.software', '9a04f07998404286ab92e65be0885f95') .set('com.microsoft.playready.hardware', - '9a04f07998404286ab92e65be0885f95') - .set('com.adobe.primetime', 'f239e769efa348509c16a903c6932efb'); + '9a04f07998404286ab92e65be0885f95'); shaka.Player.registerSupportPlugin('offline', shaka.offline.Storage.support); diff --git a/lib/util/player_configuration.js b/lib/util/player_configuration.js index 79b950e60c..a43225d09e 100644 --- a/lib/util/player_configuration.js +++ b/lib/util/player_configuration.js @@ -133,8 +133,6 @@ shaka.util.PlayerConfiguration = class { 'com.microsoft.playready', 'urn:uuid:79f0049a-4098-8642-ab92-e65be0885f95': 'com.microsoft.playready', - 'urn:uuid:f239e769-efa3-4850-9c16-a903c6932efb': - 'com.adobe.primetime', }, manifestPreprocessor: (element) => { return shaka.util.ConfigUtils.referenceParametersAndReturn( diff --git a/test/dash/dash_parser_content_protection_unit.js b/test/dash/dash_parser_content_protection_unit.js index 5a9fb51a6c..202f09de18 100644 --- a/test/dash/dash_parser_content_protection_unit.js +++ b/test/dash/dash_parser_content_protection_unit.js @@ -222,8 +222,6 @@ describe('DashParser ContentProtection', () => { ['9a04f079-9840-4286-ab92-e65be0885f95'], ['com.microsoft.playready']); testKeySystemMappings('for old PlayReady', ['79f0049a-4098-8642-ab92-e65be0885f95'], ['com.microsoft.playready']); - testKeySystemMappings('for Adobe Primetime', - ['f239e769-efa3-4850-9c16-a903c6932efb'], ['com.adobe.primetime']); testKeySystemMappings('for multiple DRMs in the specified order', [ @@ -238,11 +236,9 @@ describe('DashParser ContentProtection', () => { [ 'EDEF8BA9-79D6-4ACE-A3C8-27DCD51D21ED', '9A04F079-9840-4286-AB92-E65BE0885F95', - 'F239E769-EFA3-4850-9C16-A903C6932EFB', ], [ 'com.widevine.alpha', 'com.microsoft.playready', - 'com.adobe.primetime', ]); }); @@ -393,7 +389,6 @@ describe('DashParser ContentProtection', () => { const drmInfos = jasmine.arrayContaining([ buildDrmInfo('com.widevine.alpha'), buildDrmInfo('com.microsoft.playready'), - buildDrmInfo('com.adobe.primetime'), ]); const expected = buildExpectedManifest( /** @type {!Array.} */(drmInfos), @@ -420,7 +415,6 @@ describe('DashParser ContentProtection', () => { const drmInfos = jasmine.arrayContaining([ buildDrmInfo('com.widevine.alpha'), buildDrmInfo('com.microsoft.playready'), - buildDrmInfo('com.adobe.primetime'), ]); const expected = buildExpectedManifest( /** @type {!Array.} */(drmInfos), @@ -454,7 +448,6 @@ describe('DashParser ContentProtection', () => { // PlayReady has two associated UUIDs, so it appears twice. buildDrmInfo('com.microsoft.playready', keyIds), buildDrmInfo('com.microsoft.playready', keyIds), - buildDrmInfo('com.adobe.primetime', keyIds), ], variantKeyIds); await testDashParser(source, expected, /* ignoreDrmInfo= */ true); }); From 844c208d14fdfdbbba8fd1889134be80d6e89ddb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Velad=20Galv=C3=A1n?= Date: Wed, 31 Jan 2024 09:56:00 +0100 Subject: [PATCH 15/64] fix(Demo): Fix MSS assets (#6194) --- demo/common/assets.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/demo/common/assets.js b/demo/common/assets.js index 68aae8de64..f7bf8d00a0 100644 --- a/demo/common/assets.js +++ b/demo/common/assets.js @@ -1434,10 +1434,12 @@ shakaAssets.testAssets = [ /* iconUri= */ 'https://reference.dashif.org/dash.js/latest/samples/lib/img/mss-1.jpg', /* manifestUri= */ 'https://test.playready.microsoft.com/smoothstreaming/SSWSS720H264PR/SuperSpeedway_720.ism/Manifest', /* source= */ shakaAssets.Source.MICROSOFT) + .addKeySystem(shakaAssets.KeySystem.PLAYREADY) .addFeature(shakaAssets.Feature.MSS) .addFeature(shakaAssets.Feature.HIGH_DEFINITION) .addFeature(shakaAssets.Feature.MP4) - .addLicenseServer('com.microsoft.playready', 'https://test.playready.microsoft.com/service/rightsmanager.asmx?cfg=(persist:false,sl:150)'), + .addLicenseServer('com.microsoft.playready', 'https://test.playready.microsoft.com/service/rightsmanager.asmx?cfg=(persist:false,sl:150)') + .setMimeType('application/vnd.ms-sstr+xml'), // }}} // MPEG-5 LCEVC assets {{{ From 78c12a6265430c80568ac28193b762edce193d1f Mon Sep 17 00:00:00 2001 From: Casey Occhialini <1508707+littlespex@users.noreply.github.com> Date: Wed, 31 Jan 2024 01:21:01 -0800 Subject: [PATCH 16/64] fix(CMCD): allow session id to be configured (#6192) --- lib/util/cmcd_manager.js | 16 +++------------- test/util/cmcd_manager_unit.js | 30 +++++++++++++++++++++++++++--- 2 files changed, 30 insertions(+), 16 deletions(-) diff --git a/lib/util/cmcd_manager.js b/lib/util/cmcd_manager.js index 8773832e3f..757d67ff09 100644 --- a/lib/util/cmcd_manager.js +++ b/lib/util/cmcd_manager.js @@ -30,13 +30,6 @@ shaka.util.CmcdManager = class { /** @private {?shaka.extern.CmcdConfiguration} */ this.config_ = config; - /** - * Session ID - * - * @private {string} - */ - this.sid_ = ''; - /** * Streaming format * @@ -68,9 +61,6 @@ shaka.util.CmcdManager = class { */ configure(config) { this.config_ = config; - if (this.config_.sessionId && this.config_.sessionId != this.sid_) { - this.sid_ = ''; - } } /** @@ -336,13 +326,13 @@ shaka.util.CmcdManager = class { * @private */ createData_() { - if (!this.sid_) { - this.sid_ = this.config_.sessionId || window.crypto.randomUUID(); + if (!this.config_.sessionId) { + this.config_.sessionId = window.crypto.randomUUID(); } return { v: shaka.util.CmcdManager.Version, sf: this.sf_, - sid: this.sid_, + sid: this.config_.sessionId, cid: this.config_.contentId, mtp: this.playerInterface_.getBandwidthEstimate() / 1000, }; diff --git a/test/util/cmcd_manager_unit.js b/test/util/cmcd_manager_unit.js index dcd33b058b..76168eea3b 100644 --- a/test/util/cmcd_manager_unit.js +++ b/test/util/cmcd_manager_unit.js @@ -8,8 +8,10 @@ describe('CmcdManager', () => { const CmcdManager = shaka.util.CmcdManager; const uuidRegex = '[A-F\\d]{8}-[A-F\\d]{4}-4[A-F\\d]{3}-[89AB][A-F\\d]{3}-[A-F\\d]{12}'; + const sidRegex = new RegExp(`sid%3D%22${uuidRegex}%22`, 'i'); + const sessionId = 'c936730c-031e-4a73-976f-92bc34039c60'; const data = { - 'sid': 'c936730c-031e-4a73-976f-92bc34039c60', + 'sid': sessionId, 'cid': 'xyz', 'su': false, 'nor': '../testing/3.m4v', @@ -187,8 +189,30 @@ describe('CmcdManager', () => { const r = ObjectUtils.cloneObject(request); cmcdManager.applyManifestData(r, manifestInfo); - const regex = new RegExp(`sid%3D%22${uuidRegex}%22`, 'i'); - expect(regex.test(r.uris[0])).toBe(true); + + expect(sidRegex.test(r.uris[0])).toBe(true); + }); + + it('generates a session id via configure', () => { + config.sessionId = sid; + cmcdManager = new CmcdManager(playerInterface, config); + + const r = ObjectUtils.cloneObject(request); + cmcdManager.applyManifestData(r, manifestInfo); + expect(r.uris[0].includes(sid)).toBe(true); + + config.sessionId = sessionId; + cmcdManager.configure(config); + cmcdManager.applyManifestData(r, manifestInfo); + expect(r.uris[0].includes(sid)).toBe(false); + expect(r.uris[0].includes(sessionId)).toBe(true); + + config.sessionId = ''; + cmcdManager.configure(config); + cmcdManager.applyManifestData(r, manifestInfo); + expect(r.uris[0].includes(sid)).toBe(false); + expect(r.uris[0].includes(sessionId)).toBe(false); + expect(sidRegex.test(r.uris[0])).toBe(true); }); }); From a1c1620f09a35b53ce93feb098b5fd6388c5c3f8 Mon Sep 17 00:00:00 2001 From: Dave Nicholas Date: Wed, 31 Jan 2024 14:12:16 +0000 Subject: [PATCH 17/64] feat: Escape html codes when getting node contents (#6198) It would appear that the previous `textContent` api transformed html entities. This PR provides feature parity with the DOMParser approach. --- lib/util/tXml.js | 5 +++-- test/util/tXml_unit.js | 28 ++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/lib/util/tXml.js b/lib/util/tXml.js index 8eb7634f17..fe4a774ffa 100644 --- a/lib/util/tXml.js +++ b/lib/util/tXml.js @@ -386,8 +386,9 @@ shaka.util.TXml = class { * @return {?string} The text contents, or null if there are none. */ static getTextContents(node) { + const StringUtils = shaka.util.StringUtils; if (typeof node === 'string') { - return node; + return StringUtils.htmlUnescape(node); } const textContent = node.children.reduce( (acc, curr) => (typeof curr === 'string' ? acc + curr : acc), @@ -396,7 +397,7 @@ shaka.util.TXml = class { if (textContent === '') { return null; } - return textContent; + return StringUtils.htmlUnescape(textContent); } /** diff --git a/test/util/tXml_unit.js b/test/util/tXml_unit.js index 46f8576800..f4b67118c9 100644 --- a/test/util/tXml_unit.js +++ b/test/util/tXml_unit.js @@ -110,6 +110,34 @@ describe('tXml', () => { expect(TXml.getContents(root)).toBe(' Bar'); }); + + it('unescapes html codes', () => { + const xmlString = [ + '', + '', + ' &><', + '', + ].join('\n'); + const root = TXml.parseXmlString(xmlString, 'Root'); + goog.asserts.assert(root, 'parseFromString should succeed'); + + expect(TXml.getContents(root)).toBe('&><'); + }); + }); + + describe('getTextContents', () => { + it('unescapes html codes', () => { + const xmlString = [ + '', + '', + ' &><', + '', + ].join('\n'); + const root = TXml.parseXmlString(xmlString, 'Root'); + goog.asserts.assert(root, 'parseFromString should succeed'); + + expect(TXml.getTextContents(root)).toBe('\n &><\n'); + }); }); describe('parseAttr', () => { From b508d482c64542c4708734274fe47a3142ada028 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Velad=20Galv=C3=A1n?= Date: Wed, 31 Jan 2024 19:34:52 +0100 Subject: [PATCH 18/64] fix: Fix SegmentPrefetch in some cases (#6199) --- lib/media/segment_prefetch.js | 1 + lib/media/streaming_engine.js | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/media/segment_prefetch.js b/lib/media/segment_prefetch.js index e7c5aa90b7..012091135b 100644 --- a/lib/media/segment_prefetch.js +++ b/lib/media/segment_prefetch.js @@ -284,6 +284,7 @@ shaka.media.SegmentPrefetch = class { this.abortPrefetchedSegment_(reference); } } + this.clearInitSegments_(); } /** diff --git a/lib/media/streaming_engine.js b/lib/media/streaming_engine.js index 7d98a0b0d3..163253197c 100644 --- a/lib/media/streaming_engine.js +++ b/lib/media/streaming_engine.js @@ -1216,8 +1216,7 @@ shaka.media.StreamingEngine = class { for (const stream of this.audioPrefetchMap_.keys()) { const prefetch = this.audioPrefetchMap_.get(stream); prefetch.evict(presentationTime); - prefetch.prefetchSegmentsByTime(presentationTime, - /* fetchInit= */ true); + prefetch.prefetchSegmentsByTime(presentationTime); } } From acf1977887702ee9a1771ee2dcd1131c16660cdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Velad=20Galv=C3=A1n?= Date: Wed, 31 Jan 2024 19:35:06 +0100 Subject: [PATCH 19/64] test: Fix some tests in Safari 17 (#6202) --- test/player_integration.js | 80 +++++++++++++++++++------------------- 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/test/player_integration.js b/test/player_integration.js index 3bd10843d4..b90ea89f74 100644 --- a/test/player_integration.js +++ b/test/player_integration.js @@ -61,6 +61,46 @@ describe('Player', () => { document.body.removeChild(video); }); + describe('seek range', () => { + // Regression test for Issue #3675. + it('has a reasonable seek range after going from live to VOD', async () => { + const netEngine = player.getNetworkingEngine(); + const startTime = Date.now(); + netEngine.registerRequestFilter((type, request) => { + if (type != shaka.net.NetworkingEngine.RequestType.MANIFEST) { + return; + } + // Simulate a live stream by providing different manifests over time. + const time = (Date.now() - startTime) / 1000; + const manifestNumber = Math.min(5, Math.floor(0.5 + time / 2)); + request.uris = [ + '/base/test/test/assets/3675/dash_' + manifestNumber + '.mpd', + ]; + console.log('getting manifest', request.uris); + }); + + // Play the stream. + await player.load('/base/test/test/assets/3675/dash_0.mpd'); + await video.play(); + + // Wait for the stream to be over. + eventManager.listen(player, 'error', Util.spyFunc(onErrorSpy)); + /** @type {shaka.test.Waiter} */ + const waiter = new shaka.test.Waiter(eventManager) + .setPlayer(player) + .timeoutAfter(40) + .failOnTimeout(true); + await waiter.waitForEnd(video); + + // The stream should have transitioned to VOD by now. + expect(player.isLive()).toBe(false); + + // Check that the final seek range is as expected. + const seekRange = player.seekRange(); + expect(seekRange.end).toBeCloseTo(14); + }); + }); + describe('attach', () => { beforeEach(async () => { // To test attach, we want to construct a player without a video element @@ -908,46 +948,6 @@ describe('Player', () => { }); }); - describe('seek range', () => { - // Regression test for Issue #3675. - it('has a reasonable seek range after going from live to VOD', async () => { - const netEngine = player.getNetworkingEngine(); - const startTime = Date.now(); - netEngine.registerRequestFilter((type, request) => { - if (type != shaka.net.NetworkingEngine.RequestType.MANIFEST) { - return; - } - // Simulate a live stream by providing different manifests over time. - const time = (Date.now() - startTime) / 1000; - const manifestNumber = Math.min(5, Math.floor(0.5 + time / 2)); - request.uris = [ - '/base/test/test/assets/3675/dash_' + manifestNumber + '.mpd', - ]; - console.log('getting manifest', request.uris); - }); - - // Play the stream. - await player.load('/base/test/test/assets/3675/dash_0.mpd'); - await video.play(); - - // Wait for the stream to be over. - eventManager.listen(player, 'error', Util.spyFunc(onErrorSpy)); - /** @type {shaka.test.Waiter} */ - const waiter = new shaka.test.Waiter(eventManager) - .setPlayer(player) - .timeoutAfter(40) - .failOnTimeout(true); - await waiter.waitForEnd(video); - - // The stream should have transitioned to VOD by now. - expect(player.isLive()).toBe(false); - - // Check that the final seek range is as expected. - const seekRange = player.seekRange(); - expect(seekRange.end).toBeCloseTo(14); - }); - }); - describe('buffering', () => { const startBuffering = jasmine.objectContaining({buffering: true}); const endBuffering = jasmine.objectContaining({buffering: false}); From cac1fd0f7f8569161d8118c724333ef91b14bfef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Velad=20Galv=C3=A1n?= Date: Wed, 31 Jan 2024 19:35:22 +0100 Subject: [PATCH 20/64] fix: Prevent license requests for unplayable variants (#6204) Fixes https://github.com/shaka-project/shaka-player/issues/3429 --- lib/player.js | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/lib/player.js b/lib/player.js index 31ecaeefa1..f23f8b7644 100644 --- a/lib/player.js +++ b/lib/player.js @@ -1795,8 +1795,17 @@ shaka.Player = class extends shaka.util.FakeEventTarget { this.drmEngine_.configure(this.config_.drm); + const tracksChanged = shaka.util.StreamUtils.applyRestrictions( + this.manifest_.variants, this.config_.restrictions, this.maxHwRes_); + if (tracksChanged && this.streamingEngine_) { + this.onTracksChanged_(); + } + + const playableVariants = shaka.util.StreamUtils.getPlayableVariants( + this.manifest_.variants); + await this.drmEngine_.initForPlayback( - this.manifest_.variants, + playableVariants, this.manifest_.offlineSessionIds); await this.drmEngine_.attach(this.video_); From d9388378e7b6a3ef940f72b3bea5dfc3ba17cf11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Velad=20Galv=C3=A1n?= Date: Wed, 31 Jan 2024 19:35:35 +0100 Subject: [PATCH 21/64] fix: Fix DRM workaround for Xbox with Dolby Vision boxes (#6201) --- lib/media/content_workarounds.js | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/lib/media/content_workarounds.js b/lib/media/content_workarounds.js index 3976a77f33..9538ccb61b 100644 --- a/lib/media/content_workarounds.js +++ b/lib/media/content_workarounds.js @@ -69,6 +69,30 @@ shaka.media.ContentWorkarounds = class { }) .fullBox('encv', onEncryptionMetadataBox) .fullBox('enca', onEncryptionMetadataBox) + .fullBox('dvav', (box) => { + boxesToModify.push({ + box, + newType: ContentWorkarounds.BOX_TYPE_ENCV_, + }); + }) + .fullBox('dva1', (box) => { + boxesToModify.push({ + box, + newType: ContentWorkarounds.BOX_TYPE_ENCV_, + }); + }) + .fullBox('dvh1', (box) => { + boxesToModify.push({ + box, + newType: ContentWorkarounds.BOX_TYPE_ENCV_, + }); + }) + .fullBox('dvhe', (box) => { + boxesToModify.push({ + box, + newType: ContentWorkarounds.BOX_TYPE_ENCV_, + }); + }) .fullBox('hev1', (box) => { boxesToModify.push({ box, From 202f3082fd792f0d3346d4691fc8b64b44db46e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Velad=20Galv=C3=A1n?= Date: Wed, 31 Jan 2024 19:35:48 +0100 Subject: [PATCH 22/64] feat: Add disableTextPrefetch config (#6197) --- demo/config.js | 2 ++ externs/shaka/player.js | 5 +++++ lib/media/streaming_engine.js | 25 +++++++++++++++++++------ lib/util/player_configuration.js | 1 + 4 files changed, 27 insertions(+), 6 deletions(-) diff --git a/demo/config.js b/demo/config.js index 2a75a8e5da..1991734c46 100644 --- a/demo/config.js +++ b/demo/config.js @@ -457,6 +457,8 @@ shakaDemo.Config = class { }) .addBoolInput_('Disable Audio Prefetch', 'streaming.disableAudioPrefetch') + .addBoolInput_('Disable Text Prefetch', + 'streaming.disableTextPrefetch') .addBoolInput_('Disable Video Prefetch', 'streaming.disableVideoPrefetch') .addBoolInput_('Live Sync', 'streaming.liveSync') diff --git a/externs/shaka/player.js b/externs/shaka/player.js index a56b7f9e2f..6b8aea8f17 100644 --- a/externs/shaka/player.js +++ b/externs/shaka/player.js @@ -1161,6 +1161,7 @@ shaka.extern.ManifestConfiguration; * segmentPrefetchLimit: number, * prefetchAudioLanguages: !Array, * disableAudioPrefetch: boolean, + * disableTextPrefetch: boolean, * disableVideoPrefetch: boolean, * liveSync: boolean, * liveSyncMaxLatency: number, @@ -1294,6 +1295,10 @@ shaka.extern.ManifestConfiguration; * If set and prefetch limit is defined, it will prevent from prefetching data * for audio. * Defaults to false. + * @property {boolean} disableTextPrefetch + * If set and prefetch limit is defined, it will prevent from prefetching data + * for text. + * Defaults to false. * @property {boolean} disableVideoPrefetch * If set and prefetch limit is defined, it will prevent from prefetching data * for video. diff --git a/lib/media/streaming_engine.js b/lib/media/streaming_engine.js index 163253197c..bda8f7af36 100644 --- a/lib/media/streaming_engine.js +++ b/lib/media/streaming_engine.js @@ -206,6 +206,14 @@ shaka.media.StreamingEngine = class { this.audioPrefetchMap_.delete(stream); } } + // disable text segment prefetch if this is now set + if (config.disableTextPrefetch) { + const state = this.mediaStates_.get(ContentType.TEXT); + if (state && state.segmentPrefetch) { + state.segmentPrefetch.clearAll(); + state.segmentPrefetch = null; + } + } // disable video segment prefetch if this is now set if (config.disableVideoPrefetch) { @@ -942,12 +950,6 @@ shaka.media.StreamingEngine = class { */ createSegmentPrefetch_(stream) { const ContentType = shaka.util.ManifestParserUtils.ContentType; - if ( - stream.type !== ContentType.VIDEO && - stream.type !== ContentType.AUDIO - ) { - return null; - } if (stream.type === ContentType.VIDEO && this.config_.disableVideoPrefetch) { return null; @@ -956,6 +958,17 @@ shaka.media.StreamingEngine = class { this.config_.disableAudioPrefetch) { return null; } + const MimeUtils = shaka.util.MimeUtils; + const CEA608_MIME = MimeUtils.CEA608_CLOSED_CAPTION_MIMETYPE; + const CEA708_MIME = MimeUtils.CEA708_CLOSED_CAPTION_MIMETYPE; + if (stream.type === ContentType.TEXT && + (stream.mimeType == CEA608_MIME || stream.mimeType == CEA708_MIME)) { + return null; + } + if (stream.type === ContentType.TEXT && + this.config_.disableTextPrefetch) { + return null; + } if (this.audioPrefetchMap_.has(stream)) { return this.audioPrefetchMap_.get(stream); } diff --git a/lib/util/player_configuration.js b/lib/util/player_configuration.js index a43225d09e..d16a4c5607 100644 --- a/lib/util/player_configuration.js +++ b/lib/util/player_configuration.js @@ -224,6 +224,7 @@ shaka.util.PlayerConfiguration = class { segmentPrefetchLimit: 0, prefetchAudioLanguages: [], disableAudioPrefetch: false, + disableTextPrefetch: false, disableVideoPrefetch: false, liveSync: false, liveSyncMaxLatency: 1, From 62be6da72bd9fdb7706afb7cab18a33012f1c05a Mon Sep 17 00:00:00 2001 From: Joey Parrish Date: Wed, 31 Jan 2024 13:22:40 -0800 Subject: [PATCH 23/64] docs: Add missing license details after tXml import (#6206) --- LICENSE | 27 +++++++++++++++++++++++++++ lib/util/tXml.js | 6 ++++++ 2 files changed, 33 insertions(+) diff --git a/LICENSE b/LICENSE index 7fce21cf32..0fef70648d 100644 --- a/LICENSE +++ b/LICENSE @@ -257,3 +257,30 @@ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +----- + +Contains code from https://github.com/TobiasNickel/tXml +(See lib/util/tXml.js) + +tXml MIT License Agreement + +Copyright 2015 Tobias Nickel + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/lib/util/tXml.js b/lib/util/tXml.js index fe4a774ffa..5b13bf229b 100644 --- a/lib/util/tXml.js +++ b/lib/util/tXml.js @@ -1,3 +1,9 @@ +/*! @license + * tXml + * Copyright 2015 Tobias Nickel + * SPDX-License-Identifier: MIT + */ + goog.provide('shaka.util.TXml'); goog.require('shaka.util.StringUtils'); From 32f8dc5cf41d5a20858cee1c3c2c6eef29c9b524 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Velad=20Galv=C3=A1n?= Date: Thu, 1 Feb 2024 08:36:53 +0100 Subject: [PATCH 24/64] revert: Add chapter titles and dividers on the seek bar (#6208) re-open: https://github.com/shaka-project/shaka-player/issues/3597 --- docs/tutorials/ui-customization.md | 13 -- ui/externs/ui.js | 11 +- ui/less/range_elements.less | 33 ----- ui/seek_bar.js | 212 ----------------------------- ui/ui.js | 2 - 5 files changed, 1 insertion(+), 270 deletions(-) diff --git a/docs/tutorials/ui-customization.md b/docs/tutorials/ui-customization.md index 7bb460b485..86447319f7 100644 --- a/docs/tutorials/ui-customization.md +++ b/docs/tutorials/ui-customization.md @@ -188,19 +188,6 @@ const config = { ui.configure(config); ``` -If you've chosen to display chapters, you can specify the color for the chapter markers on -the timeline and the text color of the chapter titles that popup on hover: - ```js -const config = { - displayChapters: true, - seekBarColors: { - chapterMarks: 'rgb(27, 27, 27)', - chapterLabels: 'rgb(255, 255, 255)' - } -} -ui.configure(config); -``` - #### Configuring playback, fast forward and rewind rates The rate in which the player can play, fast forward and rewind content can be configured using the `playbackRates`, `fastForwardRates` and `rewindRates` options. diff --git a/ui/externs/ui.js b/ui/externs/ui.js index a66a184196..cd9f523a71 100644 --- a/ui/externs/ui.js +++ b/ui/externs/ui.js @@ -21,9 +21,7 @@ shaka.extern = {}; * base: string, * buffered: string, * played: string, - * adBreaks: string, - * chapterMarks: string, - * chapterLabels: string + * adBreaks: string * }} * * @property {string} base @@ -38,13 +36,6 @@ shaka.extern = {}; * @property {string} adBreaks * The CSS background color applied to the portion of the seek bar showing * when the ad breaks are scheduled to occur on the timeline. - * @property {string} chapterMarks - * The CSS border color applied to sections of the seek bar showing - * when the chapters start and end on the timeline. - * Defaults to dark grey rgb(27, 27, 27). - * @property {string} chapterLabels - * The CSS text color applied to the chapter labels that appear above the - * seek bar on hover. Defaults to white rgb(255, 255, 255). * @exportDoc */ shaka.extern.UISeekBarColors; diff --git a/ui/less/range_elements.less b/ui/less/range_elements.less index 6af646a0c0..2fbdeed88c 100644 --- a/ui/less/range_elements.less +++ b/ui/less/range_elements.less @@ -154,36 +154,3 @@ .shaka-ad-markers { .overlay-child(); } - -#shaka-player-ui-chapters-container { - width: 100%; - height: 100%; - display: flex; - flex-direction: row; - z-index: 0; -} - -.shaka-chapter { - height: 100%; - position: relative; -} - -.shaka-chapter-label { - position: relative; - top: -2.5em; - width: 100%; - text-align: center; - text-shadow: 1px 1px gray; - line-height: normal; -} - -.shaka-chapter > div:first-child { - width: 100%; - height: 100%; - border-right: 1px solid; - position: absolute; -} - -.shaka-chapter:last-child > div:first-child { - border-right: none; -} diff --git a/ui/seek_bar.js b/ui/seek_bar.js index 17c3dfeded..bef3e96501 100644 --- a/ui/seek_bar.js +++ b/ui/seek_bar.js @@ -16,7 +16,6 @@ goog.require('shaka.ui.RangeElement'); goog.require('shaka.ui.Utils'); goog.require('shaka.util.Dom'); goog.require('shaka.util.Error'); -goog.require('shaka.util.EventManager'); goog.require('shaka.util.Mp4Parser'); goog.require('shaka.util.Networking'); goog.require('shaka.util.Timer'); @@ -84,18 +83,6 @@ shaka.ui.SeekBar = class extends shaka.ui.RangeElement { this.markAdBreaks_(); }); - /** - * @private {shaka.util.EventManager} - */ - this.chaptersEventManager_ = new shaka.util.EventManager(); - - - /** @private {!HTMLElement} */ - this.chaptersContainer_ = shaka.util.Dom.createHTMLElement('div'); - this.chaptersContainer_.id = 'shaka-player-ui-chapters-container'; - this.container.appendChild(this.chaptersContainer_); - - this.setupChapters_(); /** * When user is scrubbing the seek bar - we should pause the video - see @@ -238,8 +225,6 @@ shaka.ui.SeekBar = class extends shaka.ui.RangeElement { this.adBreaksTimer_ = null; } - this.chaptersEventManager_.release(); - super.release(); } @@ -693,203 +678,6 @@ shaka.ui.SeekBar = class extends shaka.ui.RangeElement { return minutes + ':' + seconds; } } - - /** - * Sets up the chapter element creator and change handling. - * @private - */ - setupChapters_() { - let language = 'und'; - /** @type {!Array} */ - let chapters = []; - - /** - * Does a value compare on chapters. - * @param {shaka.extern.Chapter} a - * @param {shaka.extern.Chapter} b - * @return {boolean} - */ - const chaptersEqual = (a, b) => { - return (!a && !b) || (a.id === b.id && a.title === b.title && - a.startTime === b.startTime && a.endTime === b.endTime); - }; - - /** @type {function(): void} */ - const handleChapterTrackChange = () => { - let nextLanguage = 'und'; - /** @type {!Array} */ - let nextChapters = []; - - const currentLocales = this.localization.getCurrentLocales(); - for (const locale of Array.from(currentLocales)) { - nextLanguage = locale; - nextChapters = this.player.getChapters(nextLanguage); - if (nextChapters.length) { - break; - } - } - if (!nextChapters.length) { - nextLanguage = 'und'; - nextChapters = this.player.getChapters(nextLanguage); - } - - const languageChanged = nextLanguage !== language; - const chaptersChanged = chapters.length !== nextChapters.length || - !chapters.some((c, idx) => { - const n = nextChapters.at(idx); - return chaptersEqual(c, n) || - nextChapters.some((n) => chaptersEqual(c, n)); - }); - - language = nextLanguage; - chapters = nextChapters; - if (!nextChapters.length) { - this.deletePreviousChapters_(); - } else if (languageChanged || chaptersChanged) { - this.createChapterElements_(this.container, chapters); - } - }; - - handleChapterTrackChange(); - - this.eventManager.listen( - this.player, 'unloading', () => { - this.deletePreviousChapters_(); - language = 'und'; - chapters = []; - }); - - this.eventManager.listen( - this.player, 'trackschanged', handleChapterTrackChange); - - this.eventManager.listen( - this.localization, shaka.ui.Localization.LOCALE_UPDATED, () => { - handleChapterTrackChange(); - }); - - this.eventManager.listen( - this.localization, shaka.ui.Localization.LOCALE_CHANGED, () => { - handleChapterTrackChange(); - }); - } - - /** - * Builds and inserts ChaptersElement into dom container. - * @param {!HTMLElement} container - * @param {!Array} chapterTracks - * @private - */ - createChapterElements_(container, chapterTracks) { - this.deletePreviousChapters_(); - - const hiddenClass = 'shaka-hidden'; - - /** @type {{start: number, end: number}} */ - const seekRange = this.player.seekRange(); - - /** - * @type {!Array<{ - * start: number, - * end: number, - * size: number, - * title: string, - * id: string - * }>} - * */ - const chapters = []; - - for (const c of chapterTracks) { - if (c.startTime >= seekRange.end) { - continue; - } - const start = c.startTime > seekRange.start ? - c.startTime : seekRange.start; - const end = c.endTime < seekRange.end ? - c.endTime : seekRange.end; - const size = (end-start); - chapters.push({start, end, size, title: c.title, id: c.id}); - } - - if (chapters.length < 2) { - return; - } - - const totalSize = chapters.reduce((t, c) => { - t += c.size; - return t; - }, 0); - - /** - * @type {!Array<{ - * start: number, - * end: number, - * el: HTMLElement - * }>} - * */ - const chapterElMap = []; - - for (const c of chapters) { - /** @type {!HTMLElement} */ - const chapterEl = shaka.util.Dom.createHTMLElement('div'); - chapterEl.classList.add('shaka-chapter'); - chapterEl.style.width = `${c.size * 100 / totalSize}%`; - - this.chaptersContainer_.appendChild(chapterEl); - - /** @type {!HTMLElement} */ - const chapterMarker = shaka.util.Dom.createHTMLElement('div'); - chapterMarker.style.borderColor = - this.config_.seekBarColors.chapterMarks; - chapterEl.appendChild(chapterMarker); - - /** @type {!HTMLElement} */ - const chapterLabel = shaka.util.Dom.createHTMLElement('p'); - chapterLabel.classList.add('shaka-chapter-label', hiddenClass); - chapterLabel.style.color = - this.config_.seekBarColors.chapterLabels; - chapterLabel.innerText = c.title; - chapterEl.appendChild(chapterLabel); - - chapterElMap.push( - {start: c.start, end: c.end, el: chapterLabel}); - } - - // Add chapter event listeners - this.chaptersEventManager_.listen(this.bar, 'pointermove', (e) => { - if (!e.target) { - return; - } - const target = /** @type {HTMLElement} */(e.target); - - const screenXDiff = e.offsetX / target.clientWidth; - const rangeMax = parseInt(target.getAttribute('max'), 10); - const hoverVal = screenXDiff * rangeMax; - - for (const c of chapterElMap) { - const hidden = c.el.classList.contains(hiddenClass); - const inChapter = c.start <= hoverVal && hoverVal < c.end; - if (inChapter === hidden) { - c.el.classList.toggle(hiddenClass); - } - } - }, {passive: true}); - - this.chaptersEventManager_.listen(this.bar, 'pointerout', () => { - for (const c of chapterElMap) { - if (!c.el.classList.contains(hiddenClass)) { - c.el.classList.add(hiddenClass); - } - } - }, {passive: true}); - } - - /** - * @private - */ - deletePreviousChapters_() { - this.chaptersEventManager_.removeAll(); - shaka.util.Dom.removeAllChildren(this.chaptersContainer_); - } }; diff --git a/ui/ui.js b/ui/ui.js index 23b5101057..3b0f4acdbd 100644 --- a/ui/ui.js +++ b/ui/ui.js @@ -229,8 +229,6 @@ shaka.ui.Overlay = class { buffered: 'rgba(255, 255, 255, 0.54)', played: 'rgb(255, 255, 255)', adBreaks: 'rgb(255, 204, 0)', - chapterMarks: 'rgb(27, 27, 27)', - chapterLabels: 'rgb(255, 255, 255)', }, volumeBarColors: { base: 'rgba(255, 255, 255, 0.54)', From fc38aeebe364a28efc710917745dcfa4b1fd3c14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Velad=20Galv=C3=A1n?= Date: Thu, 1 Feb 2024 09:45:16 +0100 Subject: [PATCH 25/64] feat!: Prefer MSE HLS over native HLS in Apple platform when not encrypted (#6188) Our HLS implementation is stable and robust enough that we can enable it by default. --- README.md | 2 +- demo/common/assets.js | 9 --------- demo/config.js | 4 ++-- docs/tutorials/upgrade.md | 1 + externs/shaka/player.js | 5 +++-- lib/player.js | 9 +++++---- lib/util/player_configuration.js | 2 +- test/hls/hls_parser_integration.js | 2 -- test/player_unit.js | 4 ---- test/transmuxer/transmuxer_integration.js | 1 - 10 files changed, 13 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index cedf55a290..3faf57918e 100644 --- a/README.md +++ b/README.md @@ -210,7 +210,7 @@ NOTES: NOTES: - ¹: By default, FairPlay is handled using Apple's native HLS player, when on Safari. We do support FairPlay through MSE/EME, however. See the - `streaming.useNativeHlsOnSafari` configuration value. + `streaming.useNativeHlsForFairPlay` configuration value. ## Media container and subtitle support diff --git a/demo/common/assets.js b/demo/common/assets.js index f7bf8d00a0..c486dcb713 100644 --- a/demo/common/assets.js +++ b/demo/common/assets.js @@ -1456,9 +1456,6 @@ shakaAssets.testAssets = [ .addFeature(shakaAssets.Feature.LCEVC) .addDescription('LCEVC Enhanced eSports content selection.') .setExtraConfig({ - streaming: { - useNativeHlsOnSafari: false, - }, mediaSource: { forceTransmux: true, }, @@ -1498,9 +1495,6 @@ shakaAssets.testAssets = [ .addFeature(shakaAssets.Feature.OFFLINE) .addFeature(shakaAssets.Feature.LCEVC) .setExtraConfig({ - streaming: { - useNativeHlsOnSafari: false, - }, mediaSource: { forceTransmux: true, }, @@ -1522,9 +1516,6 @@ shakaAssets.testAssets = [ .addFeature(shakaAssets.Feature.OFFLINE) .addFeature(shakaAssets.Feature.LCEVC) .setExtraConfig({ - streaming: { - useNativeHlsOnSafari: false, - }, mediaSource: { forceTransmux: true, }, diff --git a/demo/config.js b/demo/config.js index 1991734c46..af191f3d3e 100644 --- a/demo/config.js +++ b/demo/config.js @@ -533,8 +533,8 @@ shakaDemo.Config = class { .addBoolInput_('Ignore Text Stream Failures', 'streaming.ignoreTextStreamFailures') .addBoolInput_('Stall Detector Enabled', 'streaming.stallEnabled') - .addBoolInput_('Use native HLS on Safari', - 'streaming.useNativeHlsOnSafari'); + .addBoolInput_('Use native HLS for FairPlay', + 'streaming.useNativeHlsForFairPlay'); this.addRetrySection_('streaming', 'Streaming Retry Parameters'); } diff --git a/docs/tutorials/upgrade.md b/docs/tutorials/upgrade.md index 2505d8e162..ce17faad09 100644 --- a/docs/tutorials/upgrade.md +++ b/docs/tutorials/upgrade.md @@ -98,6 +98,7 @@ application: (deprecated in v4.3.0) - `manifest.dash.manifestPreprocessor` callback now receives a type of `shaka.externs.xml.Node` instead of `Element`. - `manifest.mss.manifestPreprocessor` callback now receives a type of `shaka.externs.xml.Node` instead of `Element`. + - `streaming.useNativeHlsOnSafari` has removed. Now we have another config to do the same for FairPlay `streaming.useNativeHlsForFairPlay` or for HLS (any browser) `streaming.preferNativeHls`. - Plugin changes: - `Transmuxer` plugins now has three new parameters in `transmux()` method. diff --git a/externs/shaka/player.js b/externs/shaka/player.js index 6b8aea8f17..e73e7a4339 100644 --- a/externs/shaka/player.js +++ b/externs/shaka/player.js @@ -1147,7 +1147,7 @@ shaka.extern.ManifestConfiguration; * stallEnabled: boolean, * stallThreshold: number, * stallSkip: number, - * useNativeHlsOnSafari: boolean, + * useNativeHlsForFairPlay: boolean, * inaccurateManifestTolerance: number, * lowLatencyMode: boolean, * autoLowLatencyMode: boolean, @@ -1240,12 +1240,13 @@ shaka.extern.ManifestConfiguration; * been detected. If 0, the player will pause and immediately play instead of * seeking. A value of 0 is recommended and provided as default on TV * platforms (WebOS, Tizen, Chromecast, etc). - * @property {boolean} useNativeHlsOnSafari + * @property {boolean} useNativeHlsForFairPlay * Desktop Safari has both MediaSource and their native HLS implementation. * Depending on the application's needs, it may prefer one over the other. * Warning when disabled: Where single-key DRM streams work fine, multi-keys * streams is showing unexpected behaviours (stall, audio playing with video * freezes, ...). Use with care. + * Defaults to true. * @property {number} inaccurateManifestTolerance * The maximum difference, in seconds, between the times in the manifest and * the times in the segments. Larger values allow us to compensate for more diff --git a/lib/player.js b/lib/player.js index f23f8b7644..a0c3c0e576 100644 --- a/lib/player.js +++ b/lib/player.js @@ -1516,10 +1516,11 @@ shaka.Player = class extends shaka.util.FakeEventTarget { return true; } - // For Safari, we have an older flag which only applies to this one - // browser: - if (Platform.isApple()) { - return this.config_.streaming.useNativeHlsOnSafari; + // Native FairPlay HLS can be preferred on Apple platfforms. + if (Platform.isApple() && + (this.config_.drm.servers['com.apple.fps'] || + this.config_.drm.servers['com.apple.fps.1_0'])) { + return this.config_.streaming.useNativeHlsForFairPlay; } } diff --git a/lib/util/player_configuration.js b/lib/util/player_configuration.js index d16a4c5607..1604d34d2c 100644 --- a/lib/util/player_configuration.js +++ b/lib/util/player_configuration.js @@ -203,7 +203,7 @@ shaka.util.PlayerConfiguration = class { stallEnabled: true, stallThreshold: 1 /* seconds */, stallSkip: 0.1 /* seconds */, - useNativeHlsOnSafari: true, + useNativeHlsForFairPlay: true, // If we are within 2 seconds of the start of a live segment, fetch the // previous one. This allows for segment drift, but won't download an // extra segment if we aren't close to the start. diff --git a/test/hls/hls_parser_integration.js b/test/hls/hls_parser_integration.js index 19f369f913..aa1967c9b1 100644 --- a/test/hls/hls_parser_integration.js +++ b/test/hls/hls_parser_integration.js @@ -63,8 +63,6 @@ filterDescribe('HlsParser', checkNoBrokenEdgeHls, () => { player = new compiledShaka.Player(); await player.attach(video); - player.configure('streaming.useNativeHlsOnSafari', false); - // Disable stall detection, which can interfere with playback tests. player.configure('streaming.stallEnabled', false); diff --git a/test/player_unit.js b/test/player_unit.js index fe436487ba..f190d5b662 100644 --- a/test/player_unit.js +++ b/test/player_unit.js @@ -683,7 +683,6 @@ describe('Player', () => { video.canPlayType.and.returnValue('maybe'); spyOn(shaka.util.Platform, 'anyMediaElement').and.returnValue(video); spyOn(shaka.util.Platform, 'supportsMediaSource').and.returnValue(true); - spyOn(shaka.util.Platform, 'isApple').and.returnValue(false); // Make sure player.load() resolves for src= spyOn(shaka.util.MediaReadyState, 'waitForReadyState').and.callFake( (mediaElement, readyState, eventManager, callback) => { @@ -693,7 +692,6 @@ describe('Player', () => { player.configure({ streaming: { preferNativeHls: true, - useNativeHlsOnSafari: false, }, }); @@ -705,12 +703,10 @@ describe('Player', () => { it('does not apply to non-HLS streams', async () => { video.canPlayType.and.returnValue('maybe'); spyOn(shaka.util.Platform, 'supportsMediaSource').and.returnValue(true); - spyOn(shaka.util.Platform, 'isApple').and.returnValue(false); player.configure({ streaming: { preferNativeHls: true, - useNativeHlsOnSafari: false, }, }); diff --git a/test/transmuxer/transmuxer_integration.js b/test/transmuxer/transmuxer_integration.js index 0263bd9ce2..8a6a3d3f3f 100644 --- a/test/transmuxer/transmuxer_integration.js +++ b/test/transmuxer/transmuxer_integration.js @@ -106,7 +106,6 @@ filterDescribe('Transmuxer Player', checkNoBrokenEdge, () => { await player.attach(video); player.configure('mediaSource.forceTransmux', true); - player.configure('streaming.useNativeHlsOnSafari', false); // Disable stall detection, which can interfere with playback tests. player.configure('streaming.stallEnabled', false); From 67164483f32f08183912386fb6bb0f5f5913ab72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Velad=20Galv=C3=A1n?= Date: Thu, 1 Feb 2024 17:49:51 +0100 Subject: [PATCH 26/64] docs: Add specific doc on UI localization strategies (#6203) Closes https://github.com/shaka-project/shaka-player/issues/3464 --- docs/tutorials/ui-customization.md | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/docs/tutorials/ui-customization.md b/docs/tutorials/ui-customization.md index 86447319f7..44f9169142 100644 --- a/docs/tutorials/ui-customization.md +++ b/docs/tutorials/ui-customization.md @@ -273,3 +273,32 @@ PR contributions to [the gallery repo][] are welcome. [@lucksy]: https://github.com/lucksy [pre-packaged Shaka UI themes]: https://lucksy.github.io/shaka-player-themes/ [the gallery repo]: https://github.com/lucksy/shaka-player-themes + +#### Add custom localization + +Load specific locale data at runtime (adjust the URL and language as needed): +```js +const locale = 'el'; +const controls = ui.getControls(); +const localization = controls.getLocalization(); +const response = await fetch('ui/locales/' + locale + '.json'); // <----- JSON translation URL here +const translations = await response.json(); +const translation_map = new Map(Object.entries(translations)); +localization.insert(locale, translation_map); +``` + +Lazy-load any requested locale data at runtime (adjust the URL as needed): +```js +const controls = ui.getControls(); +const localization = controls.getLocalization(); + +localization.addEventListener('unknown-locales', async (e) => { + for (const locale of e.locales) { + const response = await fetch('ui/locales/' + locale + '.json'); // <----- JSON translation URL here + const translations = await response.json(); + const translation_map = new Map(Object.entries(translations)); + localization.insert(locale, translation_map); + } +}); +``` + From 62ab04895ae0e83872dc8f5143eec6ed76f29d5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wojciech=20Tyczy=C5=84ski?= Date: Thu, 1 Feb 2024 18:24:13 +0100 Subject: [PATCH 27/64] fix: Fix gitpkg.now.sh dependencies (#6211) gitpkg.now.sh dependencies started to have broken SHA for some reason which breaks CI infrastructure here & in our fork. --- package-lock.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 444e176b4e..a0addb00d5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5797,7 +5797,7 @@ "node_modules/less": { "version": "4.1.2", "resolved": "https://gitpkg.now.sh/joeyparrish/less.js/packages/less?28c63a43", - "integrity": "sha512-i5qb64PowTQ7eCLt7rlRcsNwFK9M5htl1ioP3Y/7WdU5NNpjpE8JgbUInlA97w4Vqqcd7PdCTgSBPLrs+Yvxag==", + "integrity": "sha512-AxZPQSmyVgtkNwrSXux9yYU0Kskcvj6AcAjWRmvyLAIkLaXRDN660R2XcsRNavXOr6tCQknVw5TvRtvCPiOW0Q==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -13166,7 +13166,7 @@ }, "less": { "version": "https://gitpkg.now.sh/joeyparrish/less.js/packages/less?28c63a43", - "integrity": "sha512-i5qb64PowTQ7eCLt7rlRcsNwFK9M5htl1ioP3Y/7WdU5NNpjpE8JgbUInlA97w4Vqqcd7PdCTgSBPLrs+Yvxag==", + "integrity": "sha512-AxZPQSmyVgtkNwrSXux9yYU0Kskcvj6AcAjWRmvyLAIkLaXRDN660R2XcsRNavXOr6tCQknVw5TvRtvCPiOW0Q==", "dev": true, "requires": { "copy-anything": "^2.0.1", From 278c7bc8cf8d4c8bfc12d4252300b9fc6095c4a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Velad=20Galv=C3=A1n?= Date: Thu, 1 Feb 2024 19:47:53 +0100 Subject: [PATCH 28/64] feat: Detect maximum HW resolution automatically on some platforms (#6180) --- externs/hisense.js | 16 ++++ externs/playstation.js | 31 ++++++++ externs/tizen.js | 41 ++++++++++ externs/webos.js | 19 +++++ externs/xbox.js | 43 +++++++++++ lib/cast/cast_receiver.js | 14 ---- lib/player.js | 24 +++++- lib/util/platform.js | 132 ++++++++++++++++++++++++++++++++ lib/util/stream_utils.js | 11 ++- test/cast/cast_receiver_unit.js | 34 -------- test/player_unit.js | 2 +- 11 files changed, 314 insertions(+), 53 deletions(-) create mode 100644 externs/hisense.js create mode 100644 externs/playstation.js create mode 100644 externs/tizen.js create mode 100644 externs/webos.js create mode 100644 externs/xbox.js diff --git a/externs/hisense.js b/externs/hisense.js new file mode 100644 index 0000000000..1a71e08689 --- /dev/null +++ b/externs/hisense.js @@ -0,0 +1,16 @@ +/*! @license + * Shaka Player + * Copyright 2016 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @fileoverview Externs for Hisense + * + * @externs + */ + +/** + * @return {boolean} + */ +window.Hisense_Get4KSupportState = function() {}; diff --git a/externs/playstation.js b/externs/playstation.js new file mode 100644 index 0000000000..62270992c0 --- /dev/null +++ b/externs/playstation.js @@ -0,0 +1,31 @@ +/*! @license + * Shaka Player + * Copyright 2016 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @fileoverview Externs for PlayStation + * + * @externs + */ + + +/** @const */ +var msdk = {}; + + +/** @const */ +msdk.device = {}; + + +/** + * @return {!Promise.<{resolution: string}>} + */ +msdk.device.getDisplayInfo = function() {}; + + +/** + * @return {!Promise.<{resolution: string}>} + */ +msdk.device.getDisplayInfoImmediate = function() {}; diff --git a/externs/tizen.js b/externs/tizen.js new file mode 100644 index 0000000000..5241c736f1 --- /dev/null +++ b/externs/tizen.js @@ -0,0 +1,41 @@ +/*! @license + * Shaka Player + * Copyright 2016 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @fileoverview Externs for Tizen + * @externs + */ + + +/** @const */ +var webapis = {}; + + +/** @const */ +webapis.systeminfo = {}; + + +/** + * @return {{width: number, height: number}} + */ +webapis.systeminfo.getMaxVideoResolution = function() {}; + + +/** @const */ +webapis.productinfo = {}; + + +/** + * @return {boolean} + */ +webapis.productinfo.is8KPanelSupported = function() {}; + + +/** + * @return {boolean} + */ +webapis.productinfo.isUdPanelSupported = function() {}; + diff --git a/externs/webos.js b/externs/webos.js new file mode 100644 index 0000000000..a502722c89 --- /dev/null +++ b/externs/webos.js @@ -0,0 +1,19 @@ +/*! @license + * Shaka Player + * Copyright 2016 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @fileoverview Externs for WebOS + * + * @externs + */ + + +/** @const */ +var PalmSystem = {}; + + +/** @type {string} */ +PalmSystem.deviceInfo; diff --git a/externs/xbox.js b/externs/xbox.js new file mode 100644 index 0000000000..65ffb0693d --- /dev/null +++ b/externs/xbox.js @@ -0,0 +1,43 @@ +/*! @license + * Shaka Player + * Copyright 2016 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @fileoverview Externs for Xbox + * + * @externs + */ + + +/** @const */ +var Windows = {}; + + +/** @const */ +Windows.Media = {}; + + +/** @const */ +Windows.Media.Protection = {}; + + +/** @const */ +Windows.Media.Protection.ProtectionCapabilities = class { + /** + * @param {string} type + * @param {string} keySystem + * @return {!Windows.Media.Protection.ProtectionCapabilityResult} + */ + isTypeSupported(type, keySystem) {} +}; + +/** + * @enum {string} + */ +Windows.Media.Protection.ProtectionCapabilityResult = { + notSupported: 'NotSupported', + maybe: 'Maybe', + probably: 'Probably', +}; diff --git a/lib/cast/cast_receiver.js b/lib/cast/cast_receiver.js index 97fb08ec39..6619ce7e68 100644 --- a/lib/cast/cast_receiver.js +++ b/lib/cast/cast_receiver.js @@ -287,20 +287,6 @@ shaka.cast.CastReceiver = class extends shaka.util.FakeEventTarget { this.player_, name, (event) => this.proxyEvent_('player', event)); } - // In our tests, the original Chromecast seems to have trouble decoding - // above 1080p. It would be a waste to select a higher res anyway, given - // that the device only outputs 1080p to begin with. - - // Chromecast has an extension to query the device/display's resolution. - if (cast.__platform__ && cast.__platform__.canDisplayType( - 'video/mp4; codecs="avc1.640028"; width=3840; height=2160')) { - // The device and display can both do 4k. Assume a 4k limit. - this.player_.setMaxHardwareResolution(3840, 2160); - } else { - // Chromecast has always been able to do 1080p. Assume a 1080p limit. - this.player_.setMaxHardwareResolution(1920, 1080); - } - // Do not start excluding values from update messages until the video is // fully loaded. this.eventManager_.listen(this.video_, 'loadeddata', () => { diff --git a/lib/player.js b/lib/player.js index a0c3c0e576..3ca1426b1c 100644 --- a/lib/player.js +++ b/lib/player.js @@ -1416,6 +1416,9 @@ shaka.Player = class extends shaka.util.FakeEventTarget { await this.srcEqualsInner_(startTimeOfLoad, mimeType); }, 'srcEqualsInner_'); } else { + await mutexWrapOperation(async () => { + await this.detectAndSetMaxHardwareResolution_(); + }, 'detectAndSetMaxHardwareResolution_'); if (!this.mediaSourceEngine_) { await mutexWrapOperation(async () => { await this.initializeMediaSourceEngineInner_(); @@ -5195,8 +5198,6 @@ shaka.Player = class extends shaka.util.FakeEventTarget { /** * Set the maximum resolution that the platform's hardware can handle. - * This will be called automatically by shaka.cast.CastReceiver - * to enforce limitations of the Chromecast hardware. * * @param {number} width * @param {number} height @@ -5207,6 +5208,25 @@ shaka.Player = class extends shaka.util.FakeEventTarget { this.maxHwRes_.height = height; } + /** + * Detect and set the maximum resolution that the platform's hardware can + * handle. + * + * @private + */ + async detectAndSetMaxHardwareResolution_() { + // Avoid having to detect the resolution again if it has already been + // detected or set + if (this.maxHwRes_.width != Infinity || + this.maxHwRes_.height != Infinity) { + return; + } + const maxResolution = + await shaka.util.Platform.detectMaxHardwareResolution(); + this.maxHwRes_.width = maxResolution.width; + this.maxHwRes_.height = maxResolution.height; + } + /** * Retry streaming after a streaming failure has occurred. When the player has * not loaded content or is loading content, this will be a no-op and will diff --git a/lib/util/platform.js b/lib/util/platform.js index ee66ff7c92..4504b2b56d 100644 --- a/lib/util/platform.js +++ b/lib/util/platform.js @@ -6,6 +6,7 @@ goog.provide('shaka.util.Platform'); +goog.require('shaka.log'); goog.require('shaka.util.Timer'); @@ -550,6 +551,137 @@ shaka.util.Platform = class { return false; } + + /** + * Detect the maximum resolution that the platform's hardware can handle. + * + * @return {!Promise.<{width: number, height: number}>} + */ + static async detectMaxHardwareResolution() { + const Platform = shaka.util.Platform; + const maxResolution = { + width: Infinity, + height: Infinity, + }; + + if (Platform.isChromecast()) { + // In our tests, the original Chromecast seems to have trouble decoding + // above 1080p. It would be a waste to select a higher res anyway, given + // that the device only outputs 1080p to begin with. + // Chromecast has an extension to query the device/display's resolution. + if (window.cast && cast.__platform__ && + cast.__platform__.canDisplayType && cast.__platform__.canDisplayType( + 'video/mp4; codecs="avc1.640028"; width=3840; height=2160')) { + // The device and display can both do 4k. Assume a 4k limit. + maxResolution.width = 3840; + maxResolution.height = 2160; + } else { + // Chromecast has always been able to do 1080p. Assume a 1080p limit. + maxResolution.width = 1920; + maxResolution.height = 1080; + } + } else if (Platform.isTizen()) { + maxResolution.width = 1920; + maxResolution.height = 1080; + try { + if (webapis.systeminfo && webapis.systeminfo.getMaxVideoResolution) { + const maxVideoResolution = + webapis.systeminfo.getMaxVideoResolution(); + maxResolution.width = maxVideoResolution.width; + maxResolution.height = maxVideoResolution.height; + } else { + if (webapis.productinfo.is8KPanelSupported && + webapis.productinfo.is8KPanelSupported()) { + maxResolution.width = 7680; + maxResolution.height = 4320; + } else if (webapis.productinfo.isUdPanelSupported && + webapis.productinfo.isUdPanelSupported()) { + maxResolution.width = 3840; + maxResolution.height = 2160; + } + } + } catch (e) { + shaka.log.alwaysWarn('Tizen: Error detecting screen size, default ' + + 'screen size 1920x1080.'); + } + } else if (Platform.isXboxOne()) { + const protectionCapabilities = + new Windows.Media.Protection.ProtectionCapabilities(); + const protectionResult = + Windows.Media.Protection.ProtectionCapabilityResult; + // isTypeSupported may return "maybe", which means the operation is not + // completed. This means we need to retry + // https://learn.microsoft.com/en-us/uwp/api/windows.media.protection.protectioncapabilityresult?view=winrt-22621 + let result = null; + try { + const type = + 'video/mp4;codecs="hvc1,mp4a";features="decode-res-x=3840,' + + 'decode-res-y=2160,decode-bitrate=20000,decode-fps=30,' + + 'decode-bpc=10,display-res-x=3840,display-res-y=2160,' + + 'display-bpc=8"'; + const keySystem = 'com.microsoft.playready.recommendation'; + do { + result = protectionCapabilities.isTypeSupported(type, keySystem); + } while (result === protectionResult.maybe); + } catch (e) { + result = protectionResult.notSupported; + } + if (result === protectionResult.probably) { + maxResolution.width = 3840; + maxResolution.height = 2160; + } else { + maxResolution.width = 1920; + maxResolution.height = 1080; + } + } else if (Platform.isWebOS()) { + try { + const deviceInfo = + /** @type {{screenWidth: number, screenHeight: number}} */( + JSON.parse(window.PalmSystem.deviceInfo)); + // WebOS has always been able to do 1080p. Assume a 1080p limit. + maxResolution.width = Math.max(1920, deviceInfo.screenWidth); + maxResolution.height = Math.max(1080, deviceInfo.screenHeight); + } catch (e) { + shaka.log.alwaysWarn('WebOS: Error detecting screen size, default ' + + 'screen size 1920x1080.'); + maxResolution.width = 1920; + maxResolution.height = 1080; + } + } else if (Platform.isHisense()) { + // eslint-disable-next-line new-cap + if (window.Hisense_Get4KSupportState && + // eslint-disable-next-line new-cap + window.Hisense_Get4KSupportState()) { + maxResolution.width = 3840; + maxResolution.height = 2160; + } else { + maxResolution.width = 1920; + maxResolution.height = 1080; + } + } else if (Platform.isPS4() || Platform.isPS5()) { + let supports4K = false; + try { + const result = await window.msdk.device.getDisplayInfo(); + supports4K = result.resolution === '4K'; + } catch (e) { + try { + const result = await window.msdk.device.getDisplayInfoImmediate(); + supports4K = result.resolution === '4K'; + } catch (e) { + shaka.log.alwaysWarn( + 'PlayStation: Failed to get the display info:', e); + } + } + if (supports4K) { + maxResolution.width = 3840; + maxResolution.height = 2160; + } else { + maxResolution.width = 1920; + maxResolution.height = 1080; + } + } + return maxResolution; + } }; /** @private {shaka.util.Timer} */ diff --git a/lib/util/stream_utils.js b/lib/util/stream_utils.js index ddbe64fc7a..f274a84875 100644 --- a/lib/util/stream_utils.js +++ b/lib/util/stream_utils.js @@ -263,13 +263,20 @@ shaka.util.StreamUtils = class { // |video.width| and |video.height| can be undefined, which breaks // the math, so make sure they are there first. if (video && video.width && video.height) { - if (!inRange(video.width, + let videoWidth = video.width; + let videoHeight = video.height; + if (videoHeight > videoWidth) { + // Vertical video. + [videoWidth, videoHeight] = [videoHeight, videoWidth]; + } + + if (!inRange(videoWidth, restrictions.minWidth, Math.min(restrictions.maxWidth, maxHwRes.width))) { return false; } - if (!inRange(video.height, + if (!inRange(videoHeight, restrictions.minHeight, Math.min(restrictions.maxHeight, maxHwRes.height))) { return false; diff --git a/test/cast/cast_receiver_unit.js b/test/cast/cast_receiver_unit.js index 65adfb447f..db56f245de 100644 --- a/test/cast/cast_receiver_unit.js +++ b/test/cast/cast_receiver_unit.js @@ -101,40 +101,6 @@ filterDescribe('CastReceiver', castReceiverSupport, () => { expect(Object.keys(mockPlayer.listeners).length).toBeGreaterThan(0); }); - it('limits streams to 1080p on Chromecast v1 and v2', () => { - // Simulate the canDisplayType reponse of Chromecast v1 or v2 - mockCanDisplayType.and.callFake((type) => { - const matches = /height=(\d+)/.exec(type); - const height = parseInt(matches[1], 10); - if (height && height > 1080) { - return false; - } - return true; - }); - receiver = new CastReceiver( - mockVideo, mockPlayer, Util.spyFunc(mockAppDataCallback)); - expect(mockCanDisplayType).toHaveBeenCalled(); - expect(mockPlayer.setMaxHardwareResolution) - .toHaveBeenCalledWith(1920, 1080); - }); - - it('limits streams to 4k on Chromecast Ultra', () => { - // Simulate the canDisplayType reponse of Chromecast Ultra - mockCanDisplayType.and.callFake((type) => { - const matches = /height=(\d+)/.exec(type); - const height = parseInt(matches[1], 10); - if (height && height > 2160) { - return false; - } - return true; - }); - receiver = new CastReceiver( - mockVideo, mockPlayer, Util.spyFunc(mockAppDataCallback)); - expect(mockCanDisplayType).toHaveBeenCalled(); - expect(mockPlayer.setMaxHardwareResolution) - .toHaveBeenCalledWith(3840, 2160); - }); - it('does not start polling', () => { receiver = new CastReceiver( mockVideo, mockPlayer, Util.spyFunc(mockAppDataCallback)); diff --git a/test/player_unit.js b/test/player_unit.js index f190d5b662..f83c561cf0 100644 --- a/test/player_unit.js +++ b/test/player_unit.js @@ -3516,7 +3516,7 @@ describe('Player', () => { manifest.addVariant(1, (variant) => { variant.addVideo(2, (stream) => { - stream.size(200, 1024); + stream.size(1024, 1024); }); }); From 8fc292bc28a99e715e4fa453b17865eecdb2e4b5 Mon Sep 17 00:00:00 2001 From: Gary Katsevman Date: Fri, 2 Feb 2024 02:53:21 -0500 Subject: [PATCH 29/64] feat: vod dynamic playback rate buffer control (#6172) Dynamically update playback rate to keep the buffer full. Related to https://github.com/shaka-project/shaka-player/issues/6131 --- demo/config.js | 14 ++++++++--- externs/shaka/player.js | 16 ++++++++++++- lib/player.js | 41 ++++++++++++++++++++++++++------ lib/util/player_configuration.js | 3 +++ 4 files changed, 63 insertions(+), 11 deletions(-) diff --git a/demo/config.js b/demo/config.js index af191f3d3e..ba270d2af2 100644 --- a/demo/config.js +++ b/demo/config.js @@ -476,15 +476,23 @@ shakaDemo.Config = class { /* canBeZero= */ true) .addNumberInput_('Min playback rate for live sync', 'streaming.liveSyncMinPlaybackRate', - /* canBeDecimal= */ true, - /* canBeZero= */ false) + /* canBeDecimal= */ true) .addBoolInput_('Live Sync Panic Mode', 'streaming.liveSyncPanicMode') .addNumberInput_('Live Sync Panic Mode Threshold', 'streaming.liveSyncPanicThreshold') .addBoolInput_('Allow Media Source recoveries', 'streaming.allowMediaSourceRecoveries') .addNumberInput_('Minimum time between recoveries', - 'streaming.minTimeBetweenRecoveries'); + 'streaming.minTimeBetweenRecoveries') + .addBoolInput_('VOD Dynamic Playback Rate Buffer Control', + 'streaming.vodDynamicPlaybackRate') + .addNumberInput_('VOD Dynamic Playback Rate Low Buffer Rate', + 'streaming.vodDynamicPlaybackRateLowBufferRate', + /* canBeDecimal= */ true) + .addNumberInput_('VOD Dynamic Playback Rate Buffer Ratio', + 'streaming.vodDynamicPlaybackRateBufferRatio', + /* canBeDecimal= */ true); + if (!shakaDemoMain.getNativeControlsEnabled()) { this.addBoolInput_('Always Stream Text', 'streaming.alwaysStreamText'); diff --git a/externs/shaka/player.js b/externs/shaka/player.js index e73e7a4339..d7799cf266 100644 --- a/externs/shaka/player.js +++ b/externs/shaka/player.js @@ -1171,7 +1171,10 @@ shaka.extern.ManifestConfiguration; * liveSyncPanicMode: boolean, * liveSyncPanicThreshold: number, * allowMediaSourceRecoveries: boolean, - * minTimeBetweenRecoveries: number + * minTimeBetweenRecoveries: number, + * vodDynamicPlaybackRate: boolean, + * vodDynamicPlaybackRateLowBufferRate: number, + * vodDynamicPlaybackRateBufferRatio: number * }} * * @description @@ -1338,6 +1341,17 @@ shaka.extern.ManifestConfiguration; * The minimum time between recoveries when VIDEO_ERROR is reached, in * seconds. * Defaults to 5. + * @property {boolean} vodDynamicPlaybackRate + * Adapt the playback rate of the player to keep the buffer full. Defaults to + * false. + * @property {number} vodDynamicPlaybackRateLowBufferRate + * Playback rate to use if the buffer is too small. Defaults to + * 0.95. + * @property {number} vodDynamicPlaybackRateBufferRatio + * Ratio of the bufferingGoal as the low threshold for + * setting the playback rate to + * vodDynamicPlaybackRateLowBufferRate. + * Defaults to 0.5. * @exportDoc */ shaka.extern.StreamingConfiguration; diff --git a/lib/player.js b/lib/player.js index 3ca1426b1c..d274c67dfc 100644 --- a/lib/player.js +++ b/lib/player.js @@ -2065,9 +2065,10 @@ shaka.Player = class extends shaka.util.FakeEventTarget { const isLive = this.isLive(); - if (isLive && (this.config_.streaming.liveSync || + if ((isLive && (this.config_.streaming.liveSync || this.manifest_.serviceDescription || - this.config_.streaming.liveSyncPanicMode)) { + this.config_.streaming.liveSyncPanicMode)) || + this.config_.streaming.vodDynamicPlaybackRate) { const onTimeUpdate = () => this.onTimeUpdate_(); this.loadEventManager_.listen(mediaElement, 'timeupdate', onTimeUpdate); } else if (!isLive) { @@ -2398,8 +2399,9 @@ shaka.Player = class extends shaka.util.FakeEventTarget { const isLive = this.isLive(); - if (isLive && (this.config_.streaming.liveSync || - this.config_.streaming.liveSyncPanicMode)) { + if ((isLive && (this.config_.streaming.liveSync || + this.config_.streaming.liveSyncPanicMode)) || + this.config_.streaming.vodDynamicPlaybackRate) { const onTimeUpdate = () => this.onTimeUpdate_(); this.loadEventManager_.listen(mediaElement, 'timeupdate', onTimeUpdate); } else if (!isLive) { @@ -5672,15 +5674,41 @@ shaka.Player = class extends shaka.util.FakeEventTarget { } /** - * Callback for liveSync + * Callback for liveSync and vodDynamicPlaybackRate * * @private */ onTimeUpdate_() { + const playbackRate = this.video_.playbackRate; + const isLive = this.isLive(); + + if (this.config_.streaming.vodDynamicPlaybackRate && !isLive) { + const minPlaybackRate = + this.config_.streaming.vodDynamicPlaybackRateLowBufferRate; + const bufferFullness = this.getBufferFullness(); + const bufferThreshold = + this.config_.streaming.vodDynamicPlaybackRateBufferRatio; + + if (bufferFullness <= bufferThreshold) { + if (playbackRate != minPlaybackRate) { + shaka.log.debug('Buffer fullness ratio (' + bufferFullness + ') ' + + 'is less than the vodDynamicPlaybackRateBufferRatio (' + + bufferThreshold + '). Updating playbackRate to ' + minPlaybackRate); + this.trickPlay(minPlaybackRate); + } + } else if (bufferFullness == 1) { + if (playbackRate !== this.playRateController_.getDefaultRate()) { + shaka.log.debug('Buffer is full. Cancel trick play.'); + this.cancelTrickPlay(); + } + } + } + // If the live stream has reached its end, do not sync. - if (!this.isLive()) { + if (!isLive) { return; } + const seekRange = this.seekRange(); if (!Number.isFinite(seekRange.end)) { return; @@ -5725,7 +5753,6 @@ shaka.Player = class extends shaka.util.FakeEventTarget { } } - const playbackRate = this.video_.playbackRate; const latency = seekRange.end - this.video_.currentTime; let offset = 0; // In src= mode, the seek range isn't updated frequently enough, so we need diff --git a/lib/util/player_configuration.js b/lib/util/player_configuration.js index 1604d34d2c..f662c66b06 100644 --- a/lib/util/player_configuration.js +++ b/lib/util/player_configuration.js @@ -235,6 +235,9 @@ shaka.util.PlayerConfiguration = class { liveSyncPanicThreshold: 60, allowMediaSourceRecoveries: true, minTimeBetweenRecoveries: 5, + vodDynamicPlaybackRate: false, + vodDynamicPlaybackRateLowBufferRate: 0.95, + vodDynamicPlaybackRateBufferRatio: 0.5, }; // WebOS, Tizen, Chromecast and Hisense have long hardware pipelines From 489b11a959cfb1ec50a430baabf61821869b1b04 Mon Sep 17 00:00:00 2001 From: theodab Date: Fri, 2 Feb 2024 00:27:29 -0800 Subject: [PATCH 30/64] feat: Add preload system to player (#5897) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds a new player method, preload. This asynchronous method creates a PreloadManager object, which will preload data for the given manifest, and which can be passed to the load method (in place of an asset URI) in order to apply that preloaded data. This will allow for lower load latency; if you can predict what asset will be loaded ahead of time (say, by preloading things the user is hovering their mouse over in a menu), you can load the manifest before the user presses the load button. Note that PreloadManagers are only meant to be used by the player instance that created them. Closes #880 Co-authored-by: Álvaro Velad Galván --- build/types/core | 2 + demo/asset_card.js | 47 + demo/common/asset.js | 12 + demo/custom.js | 5 +- demo/front.js | 5 +- demo/main.js | 63 +- demo/search.js | 5 +- lib/media/drm_engine.js | 9 +- lib/media/manifest_filterer.js | 219 +++++ lib/media/preload_manager.js | 798 +++++++++++++++ lib/media/segment_prefetch.js | 22 +- lib/media/streaming_engine.js | 49 +- lib/player.js | 1291 ++++++++++++------------- lib/util/error.js | 5 + test/cast/cast_utils_unit.js | 1 + test/player_integration.js | 8 + test/player_load_graph_integration.js | 45 +- test/player_unit.js | 10 + 18 files changed, 1861 insertions(+), 735 deletions(-) create mode 100644 lib/media/manifest_filterer.js create mode 100644 lib/media/preload_manager.js diff --git a/build/types/core b/build/types/core index cb1b111383..8daeaecad7 100644 --- a/build/types/core +++ b/build/types/core @@ -24,6 +24,7 @@ +../../lib/media/content_workarounds.js +../../lib/media/drm_engine.js +../../lib/media/gap_jumping_controller.js ++../../lib/media/manifest_filterer.js +../../lib/media/manifest_parser.js +../../lib/media/media_source_capabilities.js +../../lib/media/media_source_engine.js @@ -31,6 +32,7 @@ +../../lib/media/play_rate_controller.js +../../lib/media/playhead.js +../../lib/media/playhead_observer.js ++../../lib/media/preload_manager.js +../../lib/media/presentation_timeline.js +../../lib/media/quality_observer.js +../../lib/media/region_observer.js diff --git a/demo/asset_card.js b/demo/asset_card.js index 4544f8257c..89d57d9021 100644 --- a/demo/asset_card.js +++ b/demo/asset_card.js @@ -241,6 +241,53 @@ shakaDemo.AssetCard = class { this.remakeButtonsFn_(this); } + /** Adds basic buttons to the card ("play" and "preload"). */ + addBaseButtons() { + let disableButtons = false; + this.addButton('Play', async () => { + if (disableButtons) { + return; + } + disableButtons = true; + await shakaDemoMain.loadAsset(this.asset_); + this.remakeButtons(); + }); + let preloadName = 'Start Preload'; + if (this.asset_.preloadManager) { + preloadName = this.asset_.preloaded ? 'Preloaded!' : 'Preloading...'; + } else if (this.asset_.preloadFailed) { + preloadName = 'Failed to Preload!'; + } + const preloadButton = this.addButton(preloadName, async () => { + if (disableButtons) { + return; + } + disableButtons = true; + this.asset_.preloaded = false; + if (this.asset_.preloadManager) { + await this.asset_.preloadManager.destroy(); + this.asset_.preloadManager = null; + this.remakeButtons(); + } else { + try { + await shakaDemoMain.preloadAsset(this.asset_); + this.remakeButtons(); + await this.asset_.preloadManager.waitForFinish(); + this.asset_.preloaded = true; + } catch (error) { + this.asset_.preloadManager = null; + this.asset_.preloadFailed = true; + throw error; + } finally { + this.remakeButtons(); + } + } + }); + if (this.asset_.preloadFailed) { + preloadButton.disabled = true; + } + } + /** * Adds a button to the bottom of the card that controls storage behavior. * This is a separate function because it involves a significant amount of diff --git a/demo/common/asset.js b/demo/common/asset.js index 523e0ab16f..eff5b19123 100644 --- a/demo/common/asset.js +++ b/demo/common/asset.js @@ -86,6 +86,13 @@ const ShakaDemoAssetInfo = class { this.mimeType = null; + // Preload values. + /** @type {?shaka.media.PreloadManager} */ + this.preloadManager; + this.preloaded = false; + this.preloadFailed = false; + + // Offline storage values. /** @type {?function()} */ this.storeCallback; @@ -399,6 +406,11 @@ const ShakaDemoAssetInfo = class { // proper formatting. const raw = {}; for (const key in this) { + if (key.startsWith('preload') || key.startsWith('store') || + key.endsWith('Callback')) { + // These values shouldn't be saved, as they are dynamic. + continue; + } const value = this[key]; if (value instanceof Map) { // The built-in JSON functions cannot convert Maps; this converts Maps diff --git a/demo/custom.js b/demo/custom.js index a8aaf503d5..d1403b9596 100644 --- a/demo/custom.js +++ b/demo/custom.js @@ -1045,10 +1045,7 @@ shakaDemo.Custom = class { const savedList = this.savedList_; const isFeatured = false; return new shakaDemo.AssetCard(savedList, asset, isFeatured, (c) => { - c.addButton('Play', () => { - shakaDemoMain.loadAsset(asset); - this.updateSelected_(); - }); + c.addBaseButtons(); c.addButton('Edit', async () => { if (asset.unstoreCallback) { await asset.unstoreCallback(); diff --git a/demo/front.js b/demo/front.js index ee7ac4921d..07a83cdf34 100644 --- a/demo/front.js +++ b/demo/front.js @@ -119,10 +119,7 @@ shakaDemo.Front = class { if (unsupportedReason) { c.markAsUnsupported(unsupportedReason); } else { - c.addButton('Play', () => { - shakaDemoMain.loadAsset(asset); - this.updateSelected_(); - }); + c.addBaseButtons(); c.addStoreButton(); } }); diff --git a/demo/main.js b/demo/main.js index eff5131121..da16b0ae0d 100644 --- a/demo/main.js +++ b/demo/main.js @@ -1233,6 +1233,40 @@ shakaDemo.Main = class { videoBar.scrollIntoView({behavior: 'smooth', block: 'start'}); } + /** + * @param {ShakaDemoAssetInfo} asset + */ + async preloadAsset(asset) { + await this.drmConfiguration_(asset); + const manifestUri = await this.getManifestUri_(asset); + asset.preloadManager = await this.player_.preload(manifestUri); + } + + /** + * @param {ShakaDemoAssetInfo} asset + * @return {!Promise.} + * @private + */ + async getManifestUri_(asset) { + let manifestUri = asset.manifestUri; + // If we have an offline copy, use that. If the offlineUri field is null, + // we are still downloading it. + if (asset.storedContent && asset.storedContent.offlineUri) { + manifestUri = asset.storedContent.offlineUri; + } + // If it's a server side dai asset, request ad-containing manifest + // from the ad manager. + if (asset.imaAssetKey || (asset.imaContentSrcId && asset.imaVideoId)) { + manifestUri = await this.getManifestUriFromAdManager_(asset); + } + // If it's a MediaTailor asset, request ad-containing manifest + // from the ad manager. + if (asset.mediaTailorUrl) { + manifestUri = await this.getManifestUriFromMediaTailorAdManager_(asset); + } + return manifestUri; + } + /** * @param {ShakaDemoAssetInfo} asset */ @@ -1262,26 +1296,17 @@ shakaDemo.Main = class { this.controls_.getCastProxy().setAppData({'asset': asset}); // Finally, the asset can be loaded. - let manifestUri = asset.manifestUri; - // If we have an offline copy, use that. If the offlineUri field is null, - // we are still downloading it. - if (asset.storedContent && asset.storedContent.offlineUri) { - manifestUri = asset.storedContent.offlineUri; - } - // If it's a server side dai asset, request ad-containing manifest - // from the ad manager. - if (asset.imaAssetKey || (asset.imaContentSrcId && asset.imaVideoId)) { - manifestUri = await this.getManifestUriFromAdManager_(asset); - } - // If it's a MediaTailor asset, request ad-containing manifest - // from the ad manager. - if (asset.mediaTailorUrl) { - manifestUri = await this.getManifestUriFromMediaTailorAdManager_(asset); + if (asset.preloadManager) { + const preloadManager = asset.preloadManager; + asset.preloadManager = null; + await this.player_.load(preloadManager); + } else { + const manifestUri = await this.getManifestUri_(asset); + await this.player_.load( + manifestUri, + /* startTime= */ null, + asset.mimeType || undefined); } - await this.player_.load( - manifestUri, - /* startTime= */ null, - asset.mimeType || undefined); if (this.player_.isAudioOnly() && this.video_.poster == shakaDemo.Main.mainPoster_) { diff --git a/demo/search.js b/demo/search.js index 45fbf00284..4ea846b63a 100644 --- a/demo/search.js +++ b/demo/search.js @@ -146,10 +146,7 @@ shakaDemo.Search = class { if (unsupportedReason) { c.markAsUnsupported(unsupportedReason); } else { - c.addButton('Play', () => { - shakaDemoMain.loadAsset(asset); - this.updateSelected_(); - }); + c.addBaseButtons(); c.addStoreButton(); } }); diff --git a/lib/media/drm_engine.js b/lib/media/drm_engine.js index cbd49d7329..1123b633e1 100644 --- a/lib/media/drm_engine.js +++ b/lib/media/drm_engine.js @@ -35,9 +35,8 @@ goog.require('shaka.util.Uint8ArrayUtils'); shaka.media.DrmEngine = class { /** * @param {shaka.media.DrmEngine.PlayerInterface} playerInterface - * @param {number=} updateExpirationTime */ - constructor(playerInterface, updateExpirationTime = 1) { + constructor(playerInterface) { /** @private {?shaka.media.DrmEngine.PlayerInterface} */ this.playerInterface_ = playerInterface; @@ -125,7 +124,7 @@ shaka.media.DrmEngine = class { /** @private {?shaka.util.Timer} */ this.expirationTimer_ = new shaka.util.Timer(() => { this.pollExpiration_(); - }).tickEvery(/* seconds= */ updateExpirationTime); + }); // Add a catch to the Promise to avoid console logs about uncaught errors. const noop = () => {}; @@ -210,6 +209,10 @@ shaka.media.DrmEngine = class { */ configure(config) { this.config_ = config; + if (this.expirationTimer_) { + this.expirationTimer_.tickEvery( + /* seconds= */ this.config_.updateExpirationTime); + } } /** diff --git a/lib/media/manifest_filterer.js b/lib/media/manifest_filterer.js new file mode 100644 index 0000000000..6cc1a3ca46 --- /dev/null +++ b/lib/media/manifest_filterer.js @@ -0,0 +1,219 @@ +/*! @license + * Shaka Player + * Copyright 2023 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +goog.provide('shaka.media.ManifestFilterer'); + +goog.require('goog.asserts'); +goog.require('shaka.util.StreamUtils'); +goog.require('shaka.media.DrmEngine'); +goog.require('shaka.util.Error'); + +/** + * A class that handles the filtering of manifests. + * Allows for manifest filtering to be done both by the player and by a + * preload manager. + */ +shaka.media.ManifestFilterer = class { + /** + * @param {?shaka.extern.PlayerConfiguration} config + * @param {{width: number, height: number}} maxHwRes + * @param {?shaka.media.DrmEngine} drmEngine + */ + constructor(config, maxHwRes, drmEngine) { + goog.asserts.assert(config, 'Must have config'); + + /** @private {!shaka.extern.PlayerConfiguration} */ + this.config_ = config; + + /** @private {{width: number, height: number}} */ + this.maxHwRes_ = maxHwRes; + + /** @private {?shaka.media.DrmEngine} drmEngine */ + this.drmEngine_ = drmEngine; + } + + /** @param {!shaka.media.DrmEngine} drmEngine */ + setDrmEngine(drmEngine) { + this.drmEngine_ = drmEngine; + } + + /** + * Filters a manifest, removing unplayable streams/variants. + * + * @param {?shaka.extern.Manifest} manifest + * @return {!Promise.} tracksChanged + */ + async filterManifest(manifest) { + await this.filterManifestWithStreamUtils_(manifest); + return this.filterManifestWithRestrictions(manifest); + } + + /** + * Filters a manifest, removing unplayable streams/variants. + * + * @param {?shaka.extern.Manifest} manifest + * @private + */ + async filterManifestWithStreamUtils_(manifest) { + goog.asserts.assert(manifest, 'Manifest should exist!'); + await shaka.util.StreamUtils.filterManifest(this.drmEngine_, manifest); + this.checkPlayableVariants_(manifest); + } + + + /** + * @param {?shaka.extern.Manifest} manifest + * @return {boolean} tracksChanged + */ + applyRestrictions(manifest) { + return shaka.util.StreamUtils.applyRestrictions( + manifest.variants, this.config_.restrictions, this.maxHwRes_); + } + + + /** + * Apply the restrictions configuration to the manifest, and check if there's + * a variant that meets the restrictions. + * + * @param {?shaka.extern.Manifest} manifest + * @return {boolean} tracksChanged + */ + filterManifestWithRestrictions(manifest) { + const tracksChanged = this.applyRestrictions(manifest); + + if (manifest) { + // We may need to create new sessions for any new init data. + const currentDrmInfo = + this.drmEngine_ ? this.drmEngine_.getDrmInfo() : null; + // DrmEngine.newInitData() requires mediaKeys to be available. + if (currentDrmInfo && this.drmEngine_.getMediaKeys()) { + for (const variant of manifest.variants) { + this.processDrmInfos(currentDrmInfo.keySystem, variant.video); + this.processDrmInfos(currentDrmInfo.keySystem, variant.audio); + } + } + this.checkRestrictedVariants(manifest); + } + + return tracksChanged; + } + + /** + * Confirm some variants are playable. Otherwise, throw an exception. + * @param {!shaka.extern.Manifest} manifest + * @private + */ + checkPlayableVariants_(manifest) { + const valid = manifest.variants.some(shaka.util.StreamUtils.isPlayable); + + // If none of the variants are playable, throw + // CONTENT_UNSUPPORTED_BY_BROWSER. + if (!valid) { + throw new shaka.util.Error( + shaka.util.Error.Severity.CRITICAL, + shaka.util.Error.Category.MANIFEST, + shaka.util.Error.Code.CONTENT_UNSUPPORTED_BY_BROWSER); + } + } + + /** + * @param {string} keySystem + * @param {?shaka.extern.Stream} stream + */ + processDrmInfos(keySystem, stream) { + if (!stream) { + return; + } + + for (const drmInfo of stream.drmInfos) { + // Ignore any data for different key systems. + if (drmInfo.keySystem == keySystem) { + for (const initData of (drmInfo.initData || [])) { + this.drmEngine_.newInitData( + initData.initDataType, initData.initData); + } + } + } + } + + /** + * Checks if the variants are all restricted, and throw an appropriate + * exception if so. + * + * @param {shaka.extern.Manifest} manifest + */ + checkRestrictedVariants(manifest) { + const restrictedStatuses = shaka.media.ManifestFilterer.restrictedStatuses; + const keyStatusMap = + this.drmEngine_ ? this.drmEngine_.getKeyStatuses() : {}; + const keyIds = Object.keys(keyStatusMap); + const isGlobalStatus = keyIds.length && keyIds[0] == '00'; + + let hasPlayable = false; + let hasAppRestrictions = false; + + /** @type {!Set.} */ + const missingKeys = new Set(); + + /** @type {!Set.} */ + const badKeyStatuses = new Set(); + + for (const variant of manifest.variants) { + // TODO: Combine with onKeyStatus_. + const streams = []; + if (variant.audio) { + streams.push(variant.audio); + } + if (variant.video) { + streams.push(variant.video); + } + + for (const stream of streams) { + if (stream.keyIds.size) { + for (const keyId of stream.keyIds) { + const keyStatus = keyStatusMap[isGlobalStatus ? '00' : keyId]; + if (!keyStatus) { + missingKeys.add(keyId); + } else if (restrictedStatuses.includes(keyStatus)) { + badKeyStatuses.add(keyStatus); + } + } + } // if (stream.keyIds.size) + } + + if (!variant.allowedByApplication) { + hasAppRestrictions = true; + } else if (variant.allowedByKeySystem) { + hasPlayable = true; + } + } + + if (!hasPlayable) { + /** @type {shaka.extern.RestrictionInfo} */ + const data = { + hasAppRestrictions, + missingKeys: Array.from(missingKeys), + restrictedKeyStatuses: Array.from(badKeyStatuses), + }; + throw new shaka.util.Error( + shaka.util.Error.Severity.CRITICAL, + shaka.util.Error.Category.MANIFEST, + shaka.util.Error.Code.RESTRICTIONS_CANNOT_BE_MET, + data); + } + } +}; + +/** + * These are the EME key statuses that represent restricted playback. + * 'usable', 'released', 'output-downscaled', 'status-pending' are statuses + * of the usable keys. 'expired' status is being handled separately in + * DrmEngine. + * + * @const {!Array.} + */ +shaka.media.ManifestFilterer.restrictedStatuses = + ['output-restricted', 'internal-error']; diff --git a/lib/media/preload_manager.js b/lib/media/preload_manager.js new file mode 100644 index 0000000000..5d22fe410a --- /dev/null +++ b/lib/media/preload_manager.js @@ -0,0 +1,798 @@ +/*! @license + * Shaka Player + * Copyright 2023 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +goog.provide('shaka.media.PreloadManager'); + +goog.require('goog.asserts'); +goog.require('shaka.log'); +goog.require('shaka.util.Error'); +goog.require('shaka.media.ManifestFilterer'); +goog.require('shaka.media.ManifestParser'); +goog.require('shaka.util.PublicPromise'); +goog.require('shaka.media.PreferenceBasedCriteria'); +goog.require('shaka.util.Stats'); +goog.require('shaka.media.SegmentPrefetch'); +goog.require('shaka.util.IDestroyable'); +goog.require('shaka.net.NetworkingEngine'); +goog.require('shaka.media.AdaptationSetCriteria'); +goog.require('shaka.media.DrmEngine'); +goog.require('shaka.media.RegionTimeline'); +goog.require('shaka.media.QualityObserver'); +goog.require('shaka.util.StreamUtils'); +goog.require('shaka.media.StreamingEngine'); +goog.require('shaka.media.SegmentPrefetch'); +goog.require('shaka.util.ConfigUtils'); +goog.require('shaka.util.FakeEvent'); +goog.require('shaka.util.FakeEventTarget'); +goog.require('shaka.util.ObjectUtils'); +goog.require('shaka.util.PlayerConfiguration'); + +/** + * @implements {shaka.util.IDestroyable} + * @export + */ +shaka.media.PreloadManager = class extends shaka.util.FakeEventTarget { + /** + * @param {string} assetUri + * @param {?string} mimeType + * @param {number} startTimeOfLoad + * @param {?number} startTime + * @param {*} playerInterface + */ + constructor(assetUri, mimeType, startTimeOfLoad, startTime, playerInterface) { + super(); + + // Making the playerInterface a * and casting it to the right type allows + // for the PlayerInterface for this class to not be exported. + // Unfortunately, the constructor is exported by default. + const typedPlayerInterface = + /** @type {!shaka.media.PreloadManager.PlayerInterface} */ ( + playerInterface); + + /** @private {string} */ + this.assetUri_ = assetUri; + + /** @private {?string} */ + this.mimeType_ = mimeType; + + /** @private {!shaka.net.NetworkingEngine} */ + this.networkingEngine_ = typedPlayerInterface.networkingEngine; + + /** @private {?number} */ + this.startTime_ = startTime; + + /** @private {?shaka.media.AdaptationSetCriteria} */ + this.currentAdaptationSetCriteria_ = null; + + /** @private {number} */ + this.startTimeOfLoad_ = startTimeOfLoad; + + /** @private {number} */ + this.startTimeOfDrm_ = 0; + + /** @private {function():!shaka.media.DrmEngine} */ + this.createDrmEngine_ = typedPlayerInterface.createDrmEngine; + + /** @private {!shaka.media.ManifestFilterer} */ + this.manifestFilterer_ = typedPlayerInterface.manifestFilterer; + + /** @private {!shaka.extern.ManifestParser.PlayerInterface} */ + this.manifestPlayerInterface_ = + typedPlayerInterface.manifestPlayerInterface; + + /** @private {!shaka.extern.PlayerConfiguration} */ + this.config_ = typedPlayerInterface.config; + + /** @private {?shaka.extern.Manifest} */ + this.manifest_ = null; + + /** @private {?shaka.extern.ManifestParser.Factory} */ + this.parserFactory_ = null; + + /** @private {?shaka.extern.ManifestParser} */ + this.parser_ = null; + + /** @private {boolean} */ + this.parserEntrusted_ = false; + + /** @private {!shaka.media.RegionTimeline} */ + this.regionTimeline_ = typedPlayerInterface.regionTimeline; + + /** @private {boolean} */ + this.regionTimelineEntrusted_ = false; + + /** @private {?shaka.media.DrmEngine} */ + this.drmEngine_ = null; + + /** @private {boolean} */ + this.drmEngineEntrusted_ = false; + + /** @private {?shaka.extern.AbrManager.Factory} */ + this.abrManagerFactory_ = null; + + /** @private {shaka.extern.AbrManager} */ + this.abrManager_ = null; + + /** @private {boolean} */ + this.abrManagerEntrusted_ = false; + + /** @private {!Map.} */ + this.segmentPrefetchById_ = new Map(); + + /** @private {boolean} */ + this.segmentPrefetchEntrusted_ = false; + + /** @private {?shaka.media.QualityObserver} */ + this.qualityObserver_ = typedPlayerInterface.qualityObserver; + + /** @private {!shaka.util.Stats} */ + this.stats_ = new shaka.util.Stats(); + + /** @private {!shaka.util.PublicPromise} */ + this.manifestPromise_ = new shaka.util.PublicPromise(); + + /** @private {!shaka.util.PublicPromise} */ + this.drmPromise_ = new shaka.util.PublicPromise(); + + /** @private {!shaka.util.PublicPromise} */ + this.chooseInitialVariantPromise_ = new shaka.util.PublicPromise(); + + /** @private {!shaka.util.PublicPromise} */ + this.destroyPromise_ = new shaka.util.PublicPromise(); + + // Silence promise failures, in case nobody is catching this.destroyPromise_ + this.destroyPromise_.catch((error) => {}); + + /** @private {?shaka.util.FakeEventTarget} */ + this.eventHandoffTarget_ = null; + + /** @private {boolean} */ + this.destroyed_ = false; + + /** @private {boolean} */ + this.allowPrefetch_ = typedPlayerInterface.allowPrefetch; + + /** @private {?shaka.extern.Variant} */ + this.prefetchedVariant_ = null; + + /** @private {boolean} */ + this.allowMakeAbrManager_ = typedPlayerInterface.allowMakeAbrManager; + + /** @private {boolean} */ + this.hasBeenAttached_ = false; + + /** @private {?Array.} */ + this.queuedOperations_ = []; + + /** @private {?Array.} */ + this.latePhaseQueuedOperations_ = []; + } + + /** + * @param {boolean} latePhase + * @param {function()} callback + */ + addQueuedOperation(latePhase, callback) { + const queue = + latePhase ? this.latePhaseQueuedOperations_ : this.queuedOperations_; + if (queue) { + queue.push(callback); + } else { + callback(); + } + } + + /** Calls all late phase queued operations, and stops queueing them. */ + stopQueuingLatePhaseQueuedOperations() { + if (this.latePhaseQueuedOperations_) { + for (const callback of this.latePhaseQueuedOperations_) { + callback(); + } + } + this.latePhaseQueuedOperations_ = null; + } + + /** @param {!shaka.util.FakeEventTarget} eventHandoffTarget */ + setEventHandoffTarget(eventHandoffTarget) { + this.eventHandoffTarget_ = eventHandoffTarget; + this.hasBeenAttached_ = true; + // Also call all queued operations, and stop queuing them in the future. + if (this.queuedOperations_) { + for (const callback of this.queuedOperations_) { + callback(); + } + } + this.queuedOperations_ = null; + } + + /** @return {?number} */ + getStartTime() { + return this.startTime_; + } + + /** @return {number} */ + getStartTimeOfLoad() { + return this.startTimeOfLoad_; + } + + /** @return {number} */ + getStartTimeOfDRM() { + return this.startTimeOfDrm_; + } + + /** @return {?string} */ + getMimeType() { + return this.mimeType_; + } + + /** @return {string} */ + getAssetUri() { + return this.assetUri_; + } + + /** @return {?shaka.extern.Manifest} */ + getManifest() { + return this.manifest_; + } + + /** @return {?shaka.extern.ManifestParser.Factory} */ + getParserFactory() { + return this.parserFactory_; + } + + /** @return {?shaka.media.AdaptationSetCriteria} */ + getCurrentAdaptationSetCriteria() { + return this.currentAdaptationSetCriteria_; + } + + /** @return {?shaka.extern.AbrManager.Factory} */ + getAbrManagerFactory() { + return this.abrManagerFactory_; + } + + /** + * Gets the abr manager, if it exists. Also marks that the abr manager should + * not be stopped if this manager is destroyed. + * @return {?shaka.extern.AbrManager} + */ + receiveAbrManager() { + this.abrManagerEntrusted_ = true; + return this.abrManager_; + } + + /** + * @return {?shaka.extern.AbrManager} + */ + getAbrManager() { + return this.abrManager_; + } + + /** + * Gets the parser, if it exists. Also marks that the parser should not be + * stopped if this manager is destroyed. + * @return {?shaka.extern.ManifestParser} + */ + receiveParser() { + this.parserEntrusted_ = true; + return this.parser_; + } + + /** + * @return {?shaka.extern.ManifestParser} + */ + getParser() { + return this.parser_; + } + + /** + * Gets the region timeline, if it exists. Also marks that the timeline should + * not be released if this manager is destroyed. + * @return {?shaka.media.RegionTimeline} + */ + receiveRegionTimeline() { + this.regionTimelineEntrusted_ = true; + return this.regionTimeline_; + } + + /** + * @return {?shaka.media.RegionTimeline} + */ + getRegionTimeline() { + return this.regionTimeline_; + } + + /** @return {?shaka.media.QualityObserver} */ + getQualityObserver() { + return this.qualityObserver_; + } + + /** @return {!shaka.util.Stats} */ + getStats() { + return this.stats_; + } + + /** @return {!shaka.media.ManifestFilterer} */ + getManifestFilterer() { + return this.manifestFilterer_; + } + + /** + * Gets the drm engine, if it exists. Also marks that the drm engine should + * not be destroyed if this manager is destroyed. + * @return {?shaka.media.DrmEngine} + */ + receiveDrmEngine() { + this.drmEngineEntrusted_ = true; + return this.drmEngine_; + } + + /** + * @return {?shaka.media.DrmEngine} + */ + getDrmEngine() { + return this.drmEngine_; + } + + /** + * @return {?shaka.extern.Variant} + */ + getPrefetchedVariant() { + return this.prefetchedVariant_; + } + + /** + * Gets the SegmentPrefetch objects for the initial stream ids. Also marks + * that those objects should not be aborted if this manager is destroyed. + * @return {!Map.} + */ + receiveSegmentPrefetchesById() { + this.segmentPrefetchEntrusted_ = true; + return this.segmentPrefetchById_; + } + + /** @return {!Promise} */ + waitForManifest() { + return this.manifestPromise_; + } + + /** @return {!Promise} */ + waitForDrm() { + return this.drmPromise_; + } + + /** @return {!Promise} */ + waitForChooseInitialVariant() { + return this.chooseInitialVariantPromise_; + } + + /** + * Starts the process of loading the asset. + * @return {!Promise} + */ + async start() { + // Force a context switch, to give the player a chance to hook up events + // immediately if desired. + await Promise.resolve(); + + // Perform the preloading process. + try { + await this.parseManifestInner_(); + if (this.isDestroyed()) { + return; + } + this.manifestPromise_.resolve(); + await this.initializeDrmInner_(); + if (this.isDestroyed()) { + return; + } + this.drmPromise_.resolve(); + await this.chooseInitialVariantInner_(); + if (this.isDestroyed()) { + return; + } + this.chooseInitialVariantPromise_.resolve(); + } catch (error) { + this.destroyPromise_.reject(error); + throw error; + } + } + + /** + * @param {!Event} event + * @return {boolean} + * @override + */ + dispatchEvent(event) { + if (this.eventHandoffTarget_) { + return this.eventHandoffTarget_.dispatchEvent(event); + } else { + return super.dispatchEvent(event); + } + } + + /** + * @param {!shaka.util.Error} error + */ + onError(error) { + if (error.severity === shaka.util.Error.Severity.CRITICAL) { + // Cancel the loading process. + this.destroyPromise_.reject(error); + this.destroy(); + } + + const eventName = shaka.util.FakeEvent.EventName.Error; + const event = this.makeEvent_(eventName, (new Map()).set('detail', error)); + this.dispatchEvent(event); + if (event.defaultPrevented) { + error.handled = true; + } + } + + /** + * Makes a fires an event corresponding to entering a state of the loading + * process. + * @param {string} nodeName + * @private + */ + makeStateChangeEvent_(nodeName) { + this.dispatchEvent(new shaka.util.FakeEvent( + /* name= */ shaka.util.FakeEvent.EventName.OnStateChange, + /* data= */ (new Map()).set('state', nodeName))); + } + + /** + * @param {!shaka.util.FakeEvent.EventName} name + * @param {Map.=} data + * @return {!shaka.util.FakeEvent} + * @private + */ + makeEvent_(name, data) { + return new shaka.util.FakeEvent(name, data); + } + + /** + * Pick and initialize a manifest parser, then have it download and parse the + * manifest. + * + * @return {!Promise} + * @private + */ + async parseManifestInner_() { + this.makeStateChangeEvent_('manifest-parser'); + + if (!this.parser_) { + // Create the parser that we will use to parse the manifest. + this.parserFactory_ = shaka.media.ManifestParser.getFactory( + this.assetUri_, this.mimeType_); + goog.asserts.assert(this.parserFactory_, 'Must have manifest parser'); + this.parser_ = this.parserFactory_(); + + this.parser_.configure(this.config_.manifest); + } + + const startTime = Date.now() / 1000; + + this.makeStateChangeEvent_('manifest'); + + if (!this.manifest_) { + this.manifest_ = await this.parser_.start( + this.assetUri_, this.manifestPlayerInterface_); + } + + // This event is fired after the manifest is parsed, but before any + // filtering takes place. + const event = + this.makeEvent_(shaka.util.FakeEvent.EventName.ManifestParsed); + this.dispatchEvent(event); + + // We require all manifests to have at least one variant. + if (this.manifest_.variants.length == 0) { + throw new shaka.util.Error( + shaka.util.Error.Severity.CRITICAL, + shaka.util.Error.Category.MANIFEST, + shaka.util.Error.Code.NO_VARIANTS); + } + + // Make sure that all variants are either: audio-only, video-only, or + // audio-video. + shaka.media.PreloadManager.filterForAVVariants_(this.manifest_); + + const now = Date.now() / 1000; + const delta = now - startTime; + this.stats_.setManifestTime(delta); + } + + /** + * Initializes the DRM engine. + * + * @return {!Promise} + * @private + */ + async initializeDrmInner_() { + goog.asserts.assert( + this.manifest_, 'The manifest should already be parsed.'); + + this.makeStateChangeEvent_('drm-engine'); + + this.startTimeOfDrm_ = Date.now() / 1000; + + this.drmEngine_ = this.createDrmEngine_(); + this.manifestFilterer_.setDrmEngine(this.drmEngine_); + + this.drmEngine_.configure(this.config_.drm); + + const tracksChangedInitial = this.manifestFilterer_.applyRestrictions( + this.manifest_); + if (tracksChangedInitial) { + const event = this.makeEvent_( + shaka.util.FakeEvent.EventName.TracksChanged); + await Promise.resolve(); + this.dispatchEvent(event); + } + + const playableVariants = shaka.util.StreamUtils.getPlayableVariants( + this.manifest_.variants); + await this.drmEngine_.initForPlayback( + playableVariants, + this.manifest_.offlineSessionIds); + + // Now that we have drm information, filter the manifest (again) so that + // we can ensure we only use variants with the selected key system. + // const tracksChanged = + const tracksChangedAfter = await this.manifestFilterer_.filterManifest( + this.manifest_); + if (tracksChangedAfter) { + const event = this.makeEvent_( + shaka.util.FakeEvent.EventName.TracksChanged); + await Promise.resolve(); + this.dispatchEvent(event); + } + } + + /** @param {!shaka.extern.PlayerConfiguration} config */ + reconfigure(config) { + this.config_ = config; + } + + /** + * @param {string} name + * @param {*=} value + */ + configure(name, value) { + const config = shaka.util.ConfigUtils.convertToConfigObject(name, value); + shaka.util.PlayerConfiguration.mergeConfigObjects(this.config_, config); + } + + /** + * Return a copy of the current configuration. + * + * @return {shaka.extern.PlayerConfiguration} + */ + getConfiguration() { + return shaka.util.ObjectUtils.cloneObject(this.config_); + } + + /** + * Performs a final filtering of the manifest, and chooses the initial + * variant. + * + * @private + */ + chooseInitialVariantInner_() { + goog.asserts.assert( + this.manifest_, 'The manifest should already be parsed.'); + + // This step does not have any associated events, as it is only part of the + // "load" state in the old state graph. + + // Copy preferred languages from the config again, in case the config was + // changed between construction and playback. + this.currentAdaptationSetCriteria_ = + new shaka.media.PreferenceBasedCriteria( + this.config_.preferredAudioLanguage, + this.config_.preferredVariantRole, + this.config_.preferredAudioChannelCount, + this.config_.preferredVideoHdrLevel, + this.config_.preferSpatialAudio, + this.config_.preferredVideoLayout, + this.config_.preferredAudioLabel, + this.config_.preferredVideoLabel, + this.config_.mediaSource.codecSwitchingStrategy, + this.config_.manifest.dash.enableAudioGroups); + + // If the content is multi-codec and the browser can play more than one of + // them, choose codecs now before we initialize streaming. + shaka.util.StreamUtils.chooseCodecsAndFilterManifest( + this.manifest_, + this.config_.preferredVideoCodecs, + this.config_.preferredAudioCodecs, + this.config_.preferredDecodingAttributes); + + // Make the ABR manager. + if (this.allowMakeAbrManager_) { + const abrFactory = this.config_.abrFactory; + this.abrManagerFactory_ = abrFactory; + this.abrManager_ = abrFactory(); + this.abrManager_.configure(this.config_.abr); + } + + if (this.allowPrefetch_) { + const isLive = this.manifest_.presentationTimeline.isLive(); + // Prefetch segments for the predicted first variant. + // We start these here, but don't wait for them; it's okay to start the + // full load process while the segments are being prefetched. + const playableVariants = shaka.util.StreamUtils.getPlayableVariants( + this.manifest_.variants); + const adaptationSet = this.currentAdaptationSetCriteria_.create( + playableVariants); + // Guess what the first variant will be, based on a SimpleAbrManager. + this.abrManager_.configure(this.config_.abr); + this.abrManager_.setVariants(Array.from(adaptationSet.values())); + const variant = + this.abrManager_.chooseVariant(/* preferFastSwitching= */ true); + if (variant) { + this.prefetchedVariant_ = variant; + if (variant.video) { + this.makePrefetchForStream_(variant.video, isLive); + } + if (variant.audio) { + this.makePrefetchForStream_(variant.audio, isLive); + } + } + } + } + + /** + * @param {!shaka.extern.Stream} stream + * @param {boolean} isLive + * @return {!Promise} + * @private + */ + async makePrefetchForStream_(stream, isLive) { + // Use the prefetch limit from the config if this is set, otherwise use 2. + const prefetchLimit = this.config_.streaming.segmentPrefetchLimit || 2; + const prefetch = new shaka.media.SegmentPrefetch( + prefetchLimit, stream, (reference, stream, streamDataCallback) => { + return shaka.media.StreamingEngine.dispatchFetch( + reference, stream, streamDataCallback || null, + this.config_.streaming.retryParameters, this.networkingEngine_); + }); + this.segmentPrefetchById_.set(stream.id, prefetch); + + // Start prefetching a bit. + await stream.createSegmentIndex(); + const startTime = this.startTime_ || 0; + const prefetchSegmentIterator = + stream.segmentIndex.getIteratorForTime(startTime); + let prefetchSegment = + prefetchSegmentIterator ? prefetchSegmentIterator.current() : null; + if (!prefetchSegment) { + // If we can't get a segment at the desired spot, at least get a segment, + // so we can get the init segment. + prefetchSegment = stream.segmentIndex.get(0); + } + if (prefetchSegment) { + if (isLive) { + // Preload only the init segment for Live + if (prefetchSegment.initSegmentReference) { + prefetch.prefetchInitSegment(prefetchSegment.initSegmentReference); + } + } else { + // Preload a segment, too... either the first segment, or the segment + // that corresponds with this.startTime_, as appropriate. + // Note: this method also preload the init segment + prefetch.prefetchSegmentsByTime(prefetchSegment.startTime); + } + } + } + + /** + * Waits for the loading to be finished (or to fail with an error). + * @return {!Promise} + * @export + */ + waitForFinish() { + return Promise.race([ + this.chooseInitialVariantPromise_, + this.destroyPromise_, + ]); + } + + /** + * Releases or stops all non-entrusted resources. + * + * @override + * @export + */ + async destroy() { + this.destroyed_ = true; + if (this.parser_ && !this.parserEntrusted_) { + await this.parser_.stop(); + } + if (this.abrManager_ && !this.abrManagerEntrusted_) { + await this.abrManager_.stop(); + } + if (this.regionTimeline_ && !this.regionTimelineEntrusted_) { + this.regionTimeline_.release(); + } + if (this.drmEngine_ && !this.drmEngineEntrusted_) { + await this.drmEngine_.destroy(); + } + if (this.segmentPrefetchById_.size > 0 && !this.segmentPrefetchEntrusted_) { + for (const segmentPrefetch of this.segmentPrefetchById_.values()) { + segmentPrefetch.clearAll(); + } + } + // this.eventHandoffTarget_ is not unset, so that events and errors fired + // after the preload manager is destroyed will still be routed to the + // player, if it was once linked up. + } + + /** @return {boolean} */ + isDestroyed() { + return this.destroyed_; + } + + /** @return {boolean} */ + hasBeenAttached() { + return this.hasBeenAttached_; + } + + /** + * Take a series of variants and ensure that they only contain one type of + * variant. The different options are: + * 1. Audio-Video + * 2. Audio-Only + * 3. Video-Only + * + * A manifest can only contain a single type because once we initialize media + * source to expect specific streams, it must always have content for those + * streams. If we were to start with audio+video and switch to an audio-only + * variant, media source would block waiting for video content. + * + * @param {shaka.extern.Manifest} manifest + * @private + */ + static filterForAVVariants_(manifest) { + const isAVVariant = (variant) => { + // Audio-video variants may include both streams separately or may be + // single multiplexed streams with multiple codecs. + return (variant.video && variant.audio) || + (variant.video && variant.video.codecs.includes(',')); + }; + if (manifest.variants.some(isAVVariant)) { + shaka.log.debug('Found variant with audio and video content, ' + + 'so filtering out audio-only content.'); + manifest.variants = manifest.variants.filter(isAVVariant); + } + } +}; + +/** + * @typedef {{ + * config: !shaka.extern.PlayerConfiguration, + * manifestPlayerInterface: !shaka.extern.ManifestParser.PlayerInterface, + * regionTimeline: !shaka.media.RegionTimeline, + * qualityObserver: ?shaka.media.QualityObserver, + * createDrmEngine: function():!shaka.media.DrmEngine, + * networkingEngine: !shaka.net.NetworkingEngine, + * manifestFilterer: !shaka.media.ManifestFilterer, + * allowPrefetch: boolean, + * allowMakeAbrManager: boolean + * }} + * + * @property {!shaka.extern.PlayerConfiguration} config + * @property {!shaka.extern.ManifestParser.PlayerInterface} + * manifestPlayerInterface + * @property {!shaka.media.RegionTimeline} regionTimeline + * @property {?shaka.media.QualityObserver} qualityObserver + * @property {function():!shaka.media.DrmEngine} createDrmEngine + * @property {!shaka.net.NetworkingEngine} networkingEngine + * @property {!shaka.media.ManifestFilterer} manifestFilterer + * @property {boolean} allowPrefetch + * @property {boolean} allowMakeAbrManager + */ +shaka.media.PreloadManager.PlayerInterface; diff --git a/lib/media/segment_prefetch.js b/lib/media/segment_prefetch.js index 012091135b..2dc2b0b6c8 100644 --- a/lib/media/segment_prefetch.js +++ b/lib/media/segment_prefetch.js @@ -58,6 +58,16 @@ shaka.media.SegmentPrefetch = class { this.initSegmentPrefetchMap_ = new Map(); } + /** + * @param {shaka.media.SegmentPrefetch.FetchDispatcher} fetchDispatcher + */ + replaceFetchDispatcher(fetchDispatcher) { + this.fetchDispatcher_ = fetchDispatcher; + for (const operation of this.segmentPrefetchMap_.values()) { + operation.replaceFetchDispatcher(fetchDispatcher); + } + } + /** * @return {number} */ @@ -107,7 +117,7 @@ shaka.media.SegmentPrefetch = class { prefetchAllowed = false; } if (prefetchAllowed && reference.initSegmentReference) { - this.prefetchInitSegment_(reference.initSegmentReference); + this.prefetchInitSegment(reference.initSegmentReference); } if (prefetchAllowed && !this.segmentPrefetchMap_.has(reference)) { const segmentPrefetchOperation = @@ -129,9 +139,8 @@ shaka.media.SegmentPrefetch = class { * Fetch init segment. * * @param {!shaka.media.InitSegmentReference} initSegmentReference - * @private */ - prefetchInitSegment_(initSegmentReference) { + prefetchInitSegment(initSegmentReference) { goog.asserts.assert(this.prefetchLimit_ > 0, 'SegmentPrefetch can not be used when prefetchLimit <= 0.'); @@ -378,6 +387,13 @@ shaka.media.SegmentPrefetchOperation = class { this.operation_ = null; } + /** + * @param {shaka.media.SegmentPrefetch.FetchDispatcher} fetchDispatcher + */ + replaceFetchDispatcher(fetchDispatcher) { + this.fetchDispatcher_ = fetchDispatcher; + } + /** * Fetch a segments * diff --git a/lib/media/streaming_engine.js b/lib/media/streaming_engine.js index bda8f7af36..cf5e0293d1 100644 --- a/lib/media/streaming_engine.js +++ b/lib/media/streaming_engine.js @@ -253,14 +253,17 @@ shaka.media.StreamingEngine = class { * chosen by a prior call to switchTextStream(). Once the Promise resolves, * switch*() may be called freely. * + * @param {!Map.=} segmentPrefetchById + * If provided, segments prefetched for these streams will be used as needed + * during playback. * @return {!Promise} */ - async start() { + async start(segmentPrefetchById) { goog.asserts.assert(this.config_, 'StreamingEngine configure() must be called before init()!'); // Setup the initial set of Streams and then begin each update cycle. - await this.initStreams_(); + await this.initStreams_(segmentPrefetchById || (new Map())); this.destroyer_.ensureNotDestroyed(); shaka.log.debug('init: completed initial Stream setup'); @@ -842,10 +845,11 @@ shaka.media.StreamingEngine = class { * Initializes the initial streams and media states. This will schedule * updates for the given types. * + * @param {!Map.} segmentPrefetchById * @return {!Promise} * @private */ - async initStreams_() { + async initStreams_(segmentPrefetchById) { const ContentType = shaka.util.ManifestParserUtils.ContentType; goog.asserts.assert(this.config_, @@ -898,6 +902,15 @@ shaka.media.StreamingEngine = class { const stream = streamsByType.get(type); if (!this.mediaStates_.has(type)) { const mediaState = this.createMediaState_(stream); + if (segmentPrefetchById.has(stream.id)) { + const segmentPrefetch = segmentPrefetchById.get(stream.id); + segmentPrefetch.replaceFetchDispatcher( + (reference, stream, streamDataCallback) => { + return this.dispatchFetch_( + reference, stream, streamDataCallback); + }); + mediaState.segmentPrefetch = segmentPrefetch; + } this.mediaStates_.set(type, mediaState); this.scheduleUpdate_(mediaState, 0); } @@ -2430,6 +2443,27 @@ shaka.media.StreamingEngine = class { * @private */ dispatchFetch_(reference, stream, streamDataCallback) { + goog.asserts.assert( + this.playerInterface_.netEngine, 'Must have net engine'); + return shaka.media.StreamingEngine.dispatchFetch( + reference, stream, streamDataCallback || null, + this.config_.retryParameters, this.playerInterface_.netEngine); + } + + /** + * Fetches the given segment. + * + * @param {!shaka.extern.Stream} stream + * @param {(!shaka.media.InitSegmentReference|!shaka.media.SegmentReference)} + * reference + * @param {?function(BufferSource):!Promise} streamDataCallback + * @param {shaka.extern.RetryParameters} retryParameters + * @param {!shaka.net.NetworkingEngine} netEngine + * + * @return {!shaka.net.NetworkingEngine.PendingRequest} + */ + static dispatchFetch( + reference, stream, streamDataCallback, retryParameters, netEngine) { const requestType = shaka.net.NetworkingEngine.RequestType.SEGMENT; const segment = reference instanceof shaka.media.SegmentReference ? reference : undefined; @@ -2440,17 +2474,12 @@ shaka.media.StreamingEngine = class { reference.getUris(), reference.startByte, reference.endByte, - this.config_.retryParameters, + retryParameters, streamDataCallback); shaka.log.v2('fetching: reference=', reference); - return this.playerInterface_.netEngine.request( - requestType, request, { - type: type, - stream: stream, - segment: segment, - }); + return netEngine.request(requestType, request, {type, stream, segment}); } /** diff --git a/lib/player.js b/lib/player.js index d274c67dfc..0d01a889c9 100644 --- a/lib/player.js +++ b/lib/player.js @@ -14,6 +14,7 @@ goog.require('shaka.media.AdaptationSetCriteria'); goog.require('shaka.media.BufferingObserver'); goog.require('shaka.media.DrmEngine'); goog.require('shaka.media.ExampleBasedCriteria'); +goog.require('shaka.media.ManifestFilterer'); goog.require('shaka.media.ManifestParser'); goog.require('shaka.media.MediaSourceEngine'); goog.require('shaka.media.MediaSourcePlayhead'); @@ -22,10 +23,12 @@ goog.require('shaka.media.PlayRateController'); goog.require('shaka.media.Playhead'); goog.require('shaka.media.PlayheadObserverManager'); goog.require('shaka.media.PreferenceBasedCriteria'); +goog.require('shaka.media.PreloadManager'); goog.require('shaka.media.QualityObserver'); goog.require('shaka.media.RegionObserver'); goog.require('shaka.media.RegionTimeline'); goog.require('shaka.media.SegmentIndex'); +goog.require('shaka.media.SegmentPrefetch'); goog.require('shaka.media.SegmentReference'); goog.require('shaka.media.SrcEqualsPlayhead'); goog.require('shaka.media.StreamingEngine'); @@ -635,6 +638,9 @@ shaka.Player = class extends shaka.util.FakeEventTarget { /** @private {?string} */ this.assetUri_ = null; + /** @private {?string} */ + this.mimeType_ = null; + /** @private {?number} */ this.startTime_ = null; @@ -676,6 +682,10 @@ shaka.Player = class extends shaka.util.FakeEventTarget { /** @private {{width: number, height: number}} */ this.maxHwRes_ = {width: Infinity, height: Infinity}; + /** @private {!shaka.media.ManifestFilterer} */ + this.manifestFilterer_ = new shaka.media.ManifestFilterer( + this.config_, this.maxHwRes_, null); + /** @private {shaka.util.Stats} */ this.stats_ = null; @@ -814,7 +824,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget { * @return {!shaka.util.FakeEvent} * @private */ - makeEvent_(name, data) { + static makeEvent_(name, data) { return new shaka.util.FakeEvent(name, data); } @@ -997,7 +1007,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget { * @private */ makeStateChangeEvent_(nodeName) { - this.dispatchEvent(this.makeEvent_( + this.dispatchEvent(shaka.Player.makeEvent_( /* name= */ shaka.util.FakeEvent.EventName.OnStateChange, /* data= */ (new Map()).set('state', nodeName))); } @@ -1018,6 +1028,8 @@ shaka.Player = class extends shaka.util.FakeEventTarget { throw this.createAbortLoadError_(); } + const noop = this.video_ && this.video_ == mediaElement; + if (this.video_ && this.video_ != mediaElement) { await this.detach(); } @@ -1027,11 +1039,13 @@ shaka.Player = class extends shaka.util.FakeEventTarget { } try { - this.makeStateChangeEvent_('attach'); + if (!noop) { + this.makeStateChangeEvent_('attach'); - const onError = (error) => this.onVideoError_(error); - this.attachEventManager_.listen(mediaElement, 'error', onError); - this.video_ = mediaElement; + const onError = (error) => this.onVideoError_(error); + this.attachEventManager_.listen(mediaElement, 'error', onError); + this.video_ = mediaElement; + } // Only initialize media source if the platform supports it. if (initializeMediaSource && @@ -1163,7 +1177,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget { // Dispatch the unloading event. this.dispatchEvent( - this.makeEvent_(shaka.util.FakeEvent.EventName.Unloading)); + shaka.Player.makeEvent_(shaka.util.FakeEvent.EventName.Unloading)); // Release the region timeline, which is created when parsing the // manifest. @@ -1270,6 +1284,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget { } this.assetUri_ = null; + this.mimeType_ = null; this.bufferObserver_ = null; if (this.manifest_) { @@ -1324,7 +1339,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget { * Loads a new stream. * If another stream was already playing, first unloads that stream. * - * @param {string} assetUri + * @param {string|shaka.media.PreloadManager} assetUriOrPreloader * @param {?number=} startTime * When startTime is null or * undefined, playback will start at the default start time (0 @@ -1333,12 +1348,22 @@ shaka.Player = class extends shaka.util.FakeEventTarget { * @return {!Promise} * @export */ - async load(assetUri, startTime = null, mimeType) { + async load(assetUriOrPreloader, startTime = null, mimeType) { // Do not allow the player to be used after |destroy| is called. if (this.loadMode_ == shaka.Player.LoadMode.DESTROYED) { throw this.createAbortLoadError_(); } + /** @type {?shaka.media.PreloadManager} */ + let preloadManager = null; + let assetUri = ''; + if (assetUriOrPreloader instanceof shaka.media.PreloadManager) { + preloadManager = assetUriOrPreloader; + assetUri = preloadManager.getAssetUri() || ''; + } else { + assetUri = assetUriOrPreloader || ''; + } + // Quickly acquire the mutex, so this will wait for other top-level // operations. await this.mutex_.acquire('load'); @@ -1358,8 +1383,11 @@ shaka.Player = class extends shaka.util.FakeEventTarget { // Add a mechanism to detect if the load process has been interrupted by a // call to another top-level operation (unload, load, etc). const operationId = ++this.operationId_; - const detectInterruption = () => { + const detectInterruption = async () => { if (this.operationId_ != operationId) { + if (preloadManager) { + await preloadManager.destroy(); + } throw this.createAbortLoadError_(); } }; @@ -1375,37 +1403,69 @@ shaka.Player = class extends shaka.util.FakeEventTarget { const mutexWrapOperation = async (operation, mutexIdentifier) => { try { await this.mutex_.acquire(mutexIdentifier); - detectInterruption(); + await detectInterruption(); await operation(); - detectInterruption(); + await detectInterruption(); + if (preloadManager && this.config_) { + preloadManager.reconfigure(this.config_); + } } finally { this.mutex_.release(); } }; try { + if (startTime == null && preloadManager) { + startTime = preloadManager.getStartTime(); + } this.startTime_ = startTime; this.fullyLoaded_ = false; // We dispatch the loading event when someone calls |load| because we want // to surface the user intent. - this.dispatchEvent(this.makeEvent_( + this.dispatchEvent(shaka.Player.makeEvent_( shaka.util.FakeEvent.EventName.Loading)); - const startTimeOfLoad = Date.now() / 1000; + if (preloadManager) { + mimeType = preloadManager.getMimeType(); + } else if (!mimeType) { + await mutexWrapOperation(async () => { + mimeType = await this.guessMimeType_(assetUri); + }, 'guessMimeType_'); + } + + const wasPreloaded = !!preloadManager; + if (!preloadManager) { + // For simplicity, if an asset is NOT preloaded, start an internal + // "preload" here without prefetch. + // That way, both a preload and normal load can follow the same code + // paths. + preloadManager = await this.preloadInner_( + assetUri, startTime, mimeType, /* standardLoad= */ true); + if (preloadManager) { + preloadManager.setEventHandoffTarget(this); + await preloadManager.start(); + } + } else { + // Hook up events, so any events emitted by the preloadManager will + // instead be emitted by the player. + preloadManager.setEventHandoffTarget(this); + } + // Now, if there is no preload manager, that means that this is a src= + // asset. + const shouldUseSrcEquals = !preloadManager; + + const startTimeOfLoad = preloadManager ? + preloadManager.getStartTimeOfLoad() : (Date.now() / 1000); // Stats are for a single playback/load session. Stats must be initialized // before we allow calls to |updateStateHistory|. - this.stats_ = new shaka.util.Stats(); + this.stats_ = + preloadManager ? preloadManager.getStats() : new shaka.util.Stats(); this.assetUri_ = assetUri; + this.mimeType_ = mimeType || null; - if (!mimeType) { - await mutexWrapOperation(async () => { - mimeType = await this.guessMimeType_(); - }, 'guessMimeType_'); - } - const shouldUseSrcEquals = this.shouldUseSrcEquals_(assetUri, mimeType); if (shouldUseSrcEquals) { await mutexWrapOperation(async () => { goog.asserts.assert(mimeType, 'We should know the mimeType by now!'); @@ -1416,50 +1476,428 @@ shaka.Player = class extends shaka.util.FakeEventTarget { await this.srcEqualsInner_(startTimeOfLoad, mimeType); }, 'srcEqualsInner_'); } else { - await mutexWrapOperation(async () => { - await this.detectAndSetMaxHardwareResolution_(); - }, 'detectAndSetMaxHardwareResolution_'); if (!this.mediaSourceEngine_) { await mutexWrapOperation(async () => { await this.initializeMediaSourceEngineInner_(); }, 'initializeMediaSourceEngineInner_'); } + + // Get manifest and associated values from preloader. + await mutexWrapOperation( + () => preloadManager.waitForManifest(), 'waitForManifest'); + this.config_ = preloadManager.getConfiguration(); + this.manifestFilterer_ = preloadManager.getManifestFilterer(); + this.parserFactory_ = preloadManager.getParserFactory(); + this.parser_ = preloadManager.receiveParser(); + this.regionTimeline_ = preloadManager.receiveRegionTimeline(); + this.qualityObserver_ = preloadManager.getQualityObserver(); + this.manifest_ = preloadManager.getManifest(); + const currentAdaptationSetCriteria = + preloadManager.getCurrentAdaptationSetCriteria(); + if (currentAdaptationSetCriteria) { + this.currentAdaptationSetCriteria_ = currentAdaptationSetCriteria; + } + if (wasPreloaded && this.video_ && this.video_.nodeName === 'AUDIO') { + // Filter the variants to be audio-only after the fact. + // As, when preloading, we don't know if we are going to be attached + // to a video or audio element when we load, we have to do the auto + // audio-only filtering here, post-facto. + this.makeManifestAudioOnly_(); + // And continue to do so in the future. + this.configure('manifest.disableVideo', true); + } + + // Get drm engine from preloader, then finalize it. + await mutexWrapOperation( + () => preloadManager.waitForDrm(), 'waitForDrm'); + this.drmEngine_ = preloadManager.receiveDrmEngine(); await mutexWrapOperation(async () => { - await this.parseManifestInner_(mimeType); - }, 'parseManifestInner_'); - await mutexWrapOperation(async () => { - await this.initializeDrmInner_(); - }, 'initializeDrmInner_'); + await this.drmEngine_.attach(this.video_); + }, 'drmEngine_.attach'); + + // Choose an initial variant. + await mutexWrapOperation( + () => preloadManager.waitForChooseInitialVariant(), + 'waitForChooseInitialVariant'); + + // Also get the ABR manager, which has special logic related to being + // received. + const abrManagerFactory = preloadManager.getAbrManagerFactory(); + if (abrManagerFactory) { + if (!this.abrManagerFactory_ || + this.abrManagerFactory_ != abrManagerFactory) { + this.abrManager_ = preloadManager.receiveAbrManager(); + this.abrManagerFactory_ = preloadManager.getAbrManagerFactory(); + if (typeof this.abrManager_.setMediaElement != 'function') { + shaka.Deprecate.deprecateFeature(5, + 'AbrManager', + 'Please use an AbrManager with setMediaElement function.'); + this.abrManager_.setMediaElement = () => {}; + } + if (typeof this.abrManager_.setCmsdManager != 'function') { + shaka.Deprecate.deprecateFeature(5, + 'AbrManager', + 'Please use an AbrManager with setCmsdManager function.'); + this.abrManager_.setCmsdManager = () => {}; + } + if (typeof this.abrManager_.trySuggestStreams != 'function') { + shaka.Deprecate.deprecateFeature(5, + 'AbrManager', + 'Please use an AbrManager with trySuggestStreams function.'); + this.abrManager_.trySuggestStreams = () => {}; + } + } + } + + // Load the asset. + const segmentPrefetchById = + preloadManager.receiveSegmentPrefetchesById(); + const prefetchedVariant = preloadManager.getPrefetchedVariant(); await mutexWrapOperation(async () => { - await this.loadInner_(startTimeOfLoad); + await this.loadInner_( + startTimeOfLoad, prefetchedVariant, segmentPrefetchById); }, 'loadInner_'); } - this.dispatchEvent(this.makeEvent_( + this.dispatchEvent(shaka.Player.makeEvent_( shaka.util.FakeEvent.EventName.Loaded)); } catch (error) { if (error.code != shaka.util.Error.Code.LOAD_INTERRUPTED) { await this.unload(/* initializeMediaSource= */ false); + preloadManager.stopQueuingLatePhaseQueuedOperations(); } throw error; + } finally { + if (preloadManager) { + // This will cause any resources that were generated but not used to be + // properly destroyed or released. + await preloadManager.destroy(); + } + } + } + + /** + * Modifies the current manifest so that it is audio-only. + * @private + */ + makeManifestAudioOnly_() { + for (const variant of this.manifest_.variants) { + if (variant.video) { + variant.video.closeSegmentIndex(); + variant.video = null; + } + if (variant.audio && variant.audio.bandwidth) { + variant.bandwidth = variant.audio.bandwidth; + } else { + variant.bandwidth = 0; + } + } + this.manifest_.variants = this.manifest_.variants.filter((v) => { + return v.audio; + }); + } + + /** + * Starts to preload a given asset, and returns a PreloadManager object that + * represents that preloading process. + * The PreloadManager will load the manifest for that asset, as well as the + * initialization segment. It will not preload anything more than that; + * this feature is intended for reducing start-time latency, not for fully + * downloading assets before playing them (for that, use + * |shaka.offline.Storage|). + * You can pass that PreloadManager object in to the |load| method on this + * Player instance to finish loading that particular asset, or you can call + * the |destroy| method on the manager if the preload is no longer necessary. + * If this returns null rather than a PreloadManager, that indicates that the + * asset must be played with src=, which cannot be preloaded. + * + * @param {string} assetUri + * @param {?number=} startTime + * When startTime is null or + * undefined, playback will start at the default start time (0 + * for VOD and liveEdge for LIVE). + * @param {?string=} mimeType + * @return {!Promise.} + * @export + */ + async preload(assetUri, startTime = null, mimeType) { + const preloadManager = await this.preloadInner_( + assetUri, startTime, mimeType); + if (!preloadManager) { + this.onError_(new shaka.util.Error( + shaka.util.Error.Severity.CRITICAL, + shaka.util.Error.Category.PLAYER, + shaka.util.Error.Code.SRC_EQUALS_PRELOAD_NOT_SUPPORTED)); + } + preloadManager.start().catch((error) => {}); // Catch errors. + return preloadManager; + } + + /** + * @param {string} assetUri + * @param {?number} startTime + * @param {?string=} mimeType + * @param {boolean=} standardLoad + * @return {!Promise.} + * @private + */ + async preloadInner_(assetUri, startTime, mimeType, standardLoad = false) { + goog.asserts.assert(this.networkingEngine_, 'Should have a net engine!'); + goog.asserts.assert(this.config_, 'Config must not be null!'); + const startTimeOfLoad = Date.now() / 1000; + if (!mimeType) { + mimeType = await this.guessMimeType_(assetUri); + } + const shouldUseSrcEquals = this.shouldUseSrcEquals_(assetUri, mimeType); + if (shouldUseSrcEquals) { + // We cannot preload src= content. + return null; + } + let disableVideo = false; + let allowMakeAbrManager = true; + if (standardLoad) { + if (this.abrManager_ && + this.abrManagerFactory_ == this.config_.abrFactory) { + // If there's already an abr manager, don't make a new abr manager at + // all. + // In standardLoad mode, the abr manager isn't used for anything anyway, + // so it should only be created to create an abr manager for the player + // to use... which is unnecessary if we already have one of the right + // type. + allowMakeAbrManager = false; + } + if (this.video_ && this.video_.nodeName === 'AUDIO') { + disableVideo = true; + } + } + return this.makePreloadManager_( + assetUri, startTime, mimeType || null, startTimeOfLoad, + /* allowPrefetch= */ !standardLoad, disableVideo, allowMakeAbrManager); + } + + /** + * @param {string} assetUri + * @param {?number} startTime + * @param {?string} mimeType + * @param {number} startTimeOfLoad + * @param {boolean=} allowPrefetch + * @param {boolean=} disableVideo + * @param {boolean=} allowMakeAbrManager + * @return {!Promise.} + * @private + */ + async makePreloadManager_(assetUri, startTime, mimeType, startTimeOfLoad, + allowPrefetch = true, disableVideo = false, allowMakeAbrManager = true) { + goog.asserts.assert(this.networkingEngine_, 'Must have net engine'); + /** @type {?shaka.media.PreloadManager} */ + let preloadManager = null; + + const config = shaka.util.ObjectUtils.cloneObject(this.config_); + if (disableVideo) { + config.manifest.disableVideo = true; } + + const getPreloadManager = () => { + goog.asserts.assert(preloadManager, 'Must have preload manager'); + if (preloadManager.hasBeenAttached() && preloadManager.isDestroyed()) { + return null; + } + return preloadManager; + }; + + const getConfig = () => { + if (getPreloadManager()) { + return getPreloadManager().getConfiguration(); + } else { + return this.config_; + } + }; + + const setConfig = (name, value) => { + if (getPreloadManager()) { + preloadManager.configure(name, value); + } else { + this.configure(name, value); + } + }; + + // Avoid having to detect the resolution again if it has already been + // detected or set + if (this.maxHwRes_.width == Infinity && + this.maxHwRes_.height == Infinity) { + const maxResolution = + await shaka.util.Platform.detectMaxHardwareResolution(); + this.maxHwRes_.width = maxResolution.width; + this.maxHwRes_.height = maxResolution.height; + } + const manifestFilterer = new shaka.media.ManifestFilterer( + config, this.maxHwRes_, null); + const manifestPlayerInterface = { + networkingEngine: this.networkingEngine_, + filter: async (manifest) => { + const tracksChanged = await manifestFilterer.filterManifest(manifest); + if (tracksChanged) { + // Delay the 'trackschanged' event so StreamingEngine has time to + // absorb the changes before the user tries to query it. + const event = shaka.Player.makeEvent_( + shaka.util.FakeEvent.EventName.TracksChanged); + await Promise.resolve(); + preloadManager.dispatchEvent(event); + } + }, + makeTextStreamsForClosedCaptions: (manifest) => { + return this.makeTextStreamsForClosedCaptions_(manifest); + }, + + // Called when the parser finds a timeline region. This can be called + // before we start playback or during playback (live/in-progress + // manifest). + onTimelineRegionAdded: (region) => { + preloadManager.getRegionTimeline().addRegion(region); + }, + + onEvent: (event) => preloadManager.dispatchEvent(event), + onError: (error) => preloadManager.onError(error), + isLowLatencyMode: () => getConfig().streaming.lowLatencyMode, + isAutoLowLatencyMode: () => getConfig().streaming.autoLowLatencyMode, + enableLowLatencyMode: () => { + setConfig('streaming.lowLatencyMode', true); + }, + updateDuration: () => { + if (this.streamingEngine_ && preloadManager.hasBeenAttached()) { + this.streamingEngine_.updateDuration(); + } + }, + newDrmInfo: (stream) => { + // We may need to create new sessions for any new init data. + const drmEngine = preloadManager.getDrmEngine(); + const currentDrmInfo = drmEngine ? drmEngine.getDrmInfo() : null; + // DrmEngine.newInitData() requires mediaKeys to be available. + if (currentDrmInfo && drmEngine.getMediaKeys()) { + manifestFilterer.processDrmInfos(currentDrmInfo.keySystem, stream); + } + }, + onManifestUpdated: () => { + const eventName = shaka.util.FakeEvent.EventName.ManifestUpdated; + const data = (new Map()).set('isLive', this.isLive()); + preloadManager.dispatchEvent(shaka.Player.makeEvent_(eventName, data)); + + preloadManager.addQueuedOperation(false, () => { + if (this.adManager_) { + this.adManager_.onManifestUpdated(this.isLive()); + } + }); + }, + getBandwidthEstimate: () => this.abrManager_.getBandwidthEstimate(), + }; + const regionTimeline = + new shaka.media.RegionTimeline(() => this.seekRange()); + regionTimeline.addEventListener('regionadd', (event) => { + /** @type {shaka.extern.TimelineRegionInfo} */ + const region = event['region']; + this.onRegionEvent_( + shaka.util.FakeEvent.EventName.TimelineRegionAdded, region, + preloadManager); + + preloadManager.addQueuedOperation(false, () => { + if (this.adManager_) { + this.adManager_.onDashTimedMetadata(region); + } + }); + }); + let qualityObserver = null; + if (config.streaming.observeQualityChanges) { + qualityObserver = new shaka.media.QualityObserver( + () => this.getBufferedInfo()); + + qualityObserver.addEventListener('qualitychange', (event) => { + /** @type {shaka.extern.MediaQualityInfo} */ + const mediaQualityInfo = event['quality']; + /** @type {number} */ + const position = event['position']; + this.onMediaQualityChange_(mediaQualityInfo, position); + }); + } + let firstEvent = true; + const drmPlayerInterface = { + netEngine: this.networkingEngine_, + onError: (e) => preloadManager.onError(e), + onKeyStatus: (map) => { + preloadManager.addQueuedOperation(true, () => { + this.onKeyStatus_(map); + }); + }, + onExpirationUpdated: (id, expiration) => { + const event = shaka.Player.makeEvent_( + shaka.util.FakeEvent.EventName.ExpirationUpdated); + preloadManager.dispatchEvent(event); + const parser = preloadManager.getParser(); + if (parser && parser.onExpirationUpdated) { + parser.onExpirationUpdated(id, expiration); + } + }, + onEvent: (e) => { + preloadManager.dispatchEvent(e); + if (e.type == shaka.util.FakeEvent.EventName.DrmSessionUpdate && + firstEvent) { + firstEvent = false; + const now = Date.now() / 1000; + const delta = now - preloadManager.getStartTimeOfDRM(); + const stats = this.stats_ || preloadManager.getStats(); + stats.setDrmTime(delta); + // LCEVC data by itself is not encrypted in DRM protected streams + // and can therefore be accessed and decoded as normal. However, + // the LCEVC decoder needs access to the VideoElement output in + // order to apply the enhancement. In DRM contexts where the + // browser CDM restricts access from our decoder, the enhancement + // cannot be applied and therefore the LCEVC output canvas is + // hidden accordingly. + if (this.lcevcDec_) { + this.lcevcDec_.hideCanvas(); + } + } + }, + }; + + // Sadly, as the network engine creation code must be replaceable by tests, + // it cannot be made and use the utilities defined in this function. + const networkingEngine = this.createNetworkingEngine(getPreloadManager); + + /** @return {!shaka.media.DrmEngine} */ + const createDrmEngine = () => { + return this.createDrmEngine(drmPlayerInterface); + }; + /** @type {!shaka.media.PreloadManager.PlayerInterface} */ + const playerInterface = { + config, + manifestPlayerInterface, + regionTimeline, + qualityObserver, + createDrmEngine, + manifestFilterer, + networkingEngine, + allowPrefetch, + allowMakeAbrManager, + }; + preloadManager = new shaka.media.PreloadManager( + assetUri, mimeType, startTimeOfLoad, startTime, playerInterface); + return preloadManager; } /** * Determines the mimeType of the given asset, if we are not told that inside * the loading process. * + * @param {string} assetUri * @return {!Promise.} mimeType * @private */ - async guessMimeType_() { - goog.asserts.assert(this.assetUri_, 'should have a uri by now.'); - + async guessMimeType_(assetUri) { // If no MIME type is provided, and we can't base it on extension, make a // HEAD request to determine it. goog.asserts.assert(this.networkingEngine_, 'Should have a net engine!'); const retryParams = this.config_.manifest.retryParameters; let mimeType = await shaka.net.NetworkingUtils.getMimeType( - this.assetUri_, this.networkingEngine_, retryParams); + assetUri, this.networkingEngine_, retryParams); if (mimeType == 'application/x-mpegurl' && shaka.util.Platform.isApple()) { mimeType = 'application/vnd.apple.mpegurl'; } @@ -1532,307 +1970,76 @@ shaka.Player = class extends shaka.util.FakeEventTarget { } // Unless there are good reasons to use src= (single-file playback or native - // HLS), we prefer MediaSource. So the final return value for choosing src= - // is false. - return false; - } - - /** - * Initializes the media source engine. - * - * @return {!Promise} - * @private - */ - async initializeMediaSourceEngineInner_() { - goog.asserts.assert( - shaka.util.Platform.supportsMediaSource(), - 'We should not be initializing media source on a platform that ' + - 'does not support media source.'); - goog.asserts.assert( - this.video_, - 'We should have a media element when initializing media source.'); - goog.asserts.assert( - this.mediaSourceEngine_ == null, - 'We should not have a media source engine yet.'); - - this.makeStateChangeEvent_('media-source'); - - // When changing text visibility we need to update both the text displayer - // and streaming engine because we don't always stream text. To ensure - // that the text displayer and streaming engine are always in sync, wait - // until they are both initialized before setting the initial value. - const textDisplayerFactory = this.config_.textDisplayFactory; - const textDisplayer = textDisplayerFactory(); - this.lastTextFactory_ = textDisplayerFactory; - - const mediaSourceEngine = this.createMediaSourceEngine( - this.video_, - textDisplayer, - (metadata, offset, endTime) => { - this.processTimedMetadataMediaSrc_(metadata, offset, endTime); - }, - this.lcevcDec_); - mediaSourceEngine.configure(this.config_.mediaSource); - const {segmentRelativeVttTiming} = this.config_.manifest; - mediaSourceEngine.setSegmentRelativeVttTiming(segmentRelativeVttTiming); - - // Wait for media source engine to finish opening. This promise should - // NEVER be rejected as per the media source engine implementation. - await mediaSourceEngine.open(); - - // Wait until it is ready to actually store the reference. - this.mediaSourceEngine_ = mediaSourceEngine; - } - - /** - * Pick an initialize a manifest parser, then have it download and parse the - * manifest. - * - * @param {?string=} mimeType - * @return {!Promise} - * @private - */ - async parseManifestInner_(mimeType) { - goog.asserts.assert( - this.assetUri_, - 'should have a uri when making the parser.'); - goog.asserts.assert( - this.video_, - 'We should have a media element when initializing the parser.'); - goog.asserts.assert( - this.networkingEngine_, - 'Need networking engine when initializing the parser.'); - goog.asserts.assert( - this.cmcdManager_, - 'Need CMCD manager to populate manifest request data.'); - goog.asserts.assert( - this.cmsdManager_, - 'Need CMSD manager to process response headers.'); - goog.asserts.assert( - this.config_, - 'Need player config when initializing the parser.'); - - // Store references to things we asserted so that we don't need to - // reassert them again later. - const networkingEngine = this.networkingEngine_; - - this.makeStateChangeEvent_('manifest-parser'); - - // Create the parser that we will use to parse the manifest. - this.parserFactory_ = shaka.media.ManifestParser.getFactory( - this.assetUri_, - mimeType || null); - goog.asserts.assert(this.parserFactory_, 'Must have manifest parser'); - this.parser_ = this.parserFactory_(); - - const manifestConfig = - shaka.util.ObjectUtils.cloneObject(this.config_.manifest); - // Don't read video segments if the player is attached to an audio element - if (this.video_ && this.video_.nodeName === 'AUDIO') { - manifestConfig.disableVideo = true; - } - - this.parser_.configure(manifestConfig); - - // This will be needed by the parser once it starts parsing, so we will - // initialize it now even through it appears a little out-of-place. - this.regionTimeline_ = - new shaka.media.RegionTimeline(() => this.seekRange()); - this.regionTimeline_.addEventListener('regionadd', (event) => { - /** @type {shaka.extern.TimelineRegionInfo} */ - const region = event['region']; - this.onRegionEvent_( - shaka.util.FakeEvent.EventName.TimelineRegionAdded, region); - - if (this.adManager_) { - this.adManager_.onDashTimedMetadata(region); - } - }); - - this.qualityObserver_ = null; - if (this.config_.streaming.observeQualityChanges) { - this.qualityObserver_ = new shaka.media.QualityObserver( - () => this.getBufferedInfo()); - - this.qualityObserver_.addEventListener('qualitychange', (event) => { - /** @type {shaka.extern.MediaQualityInfo} */ - const mediaQualityInfo = event['quality']; - /** @type {number} */ - const position = event['position']; - this.onMediaQualityChange_(mediaQualityInfo, position); - }); - } - - const playerInterface = { - networkingEngine: networkingEngine, - filter: (manifest) => this.filterManifest_(manifest), - makeTextStreamsForClosedCaptions: (manifest) => { - return this.makeTextStreamsForClosedCaptions_(manifest); - }, - - // Called when the parser finds a timeline region. This can be called - // before we start playback or during playback (live/in-progress - // manifest). - onTimelineRegionAdded: (region) => { - this.regionTimeline_.addRegion(region); - }, - - onEvent: (event) => this.dispatchEvent(event), - onError: (error) => this.onError_(error), - isLowLatencyMode: () => this.isLowLatencyMode_(), - isAutoLowLatencyMode: () => this.isAutoLowLatencyMode_(), - enableLowLatencyMode: () => { - this.configure('streaming.lowLatencyMode', true); - }, - updateDuration: () => { - if (this.streamingEngine_) { - this.streamingEngine_.updateDuration(); - } - }, - newDrmInfo: (stream) => { - // We may need to create new sessions for any new init data. - const currentDrmInfo = - this.drmEngine_ ? this.drmEngine_.getDrmInfo() : null; - // DrmEngine.newInitData() requires mediaKeys to be available. - if (currentDrmInfo && this.drmEngine_.getMediaKeys()) { - this.processDrmInfos_(currentDrmInfo.keySystem, stream); - } - }, - onManifestUpdated: () => { - const eventName = shaka.util.FakeEvent.EventName.ManifestUpdated; - const data = (new Map()).set('isLive', this.isLive()); - this.dispatchEvent(this.makeEvent_(eventName, data)); - if (this.adManager_) { - this.adManager_.onManifestUpdated(this.isLive()); - } - }, - getBandwidthEstimate: () => this.abrManager_.getBandwidthEstimate(), - }; - - const startTime = Date.now() / 1000; - - this.makeStateChangeEvent_('manifest'); - - this.manifest_ = await this.parser_.start( - this.assetUri_, playerInterface); - - // This event is fired after the manifest is parsed, but before any - // filtering takes place. - const event = - this.makeEvent_(shaka.util.FakeEvent.EventName.ManifestParsed); - this.dispatchEvent(event); - - // We require all manifests to have at least one variant. - if (this.manifest_.variants.length == 0) { - throw new shaka.util.Error( - shaka.util.Error.Severity.CRITICAL, - shaka.util.Error.Category.MANIFEST, - shaka.util.Error.Code.NO_VARIANTS); - } - - // Make sure that all variants are either: audio-only, video-only, or - // audio-video. - shaka.Player.filterForAVVariants_(this.manifest_); - - const now = Date.now() / 1000; - const delta = now - startTime; - this.stats_.setManifestTime(delta); + // HLS), we prefer MediaSource. So the final return value for choosing src= + // is false. + return false; } /** - * Initializes the DRM engine. + * Initializes the media source engine. * * @return {!Promise} * @private */ - async initializeDrmInner_() { - goog.asserts.assert( - this.networkingEngine_, - '|onInitializeDrm_| should never be called after |destroy|'); - goog.asserts.assert( - this.config_, - '|onInitializeDrm_| should never be called after |destroy|'); + async initializeMediaSourceEngineInner_() { goog.asserts.assert( - this.manifest_, - '|this.manifest_| should have been set in an earlier step.'); + shaka.util.Platform.supportsMediaSource(), + 'We should not be initializing media source on a platform that ' + + 'does not support media source.'); goog.asserts.assert( this.video_, - 'We should have a media element when initializing the DRM Engine.'); - - this.makeStateChangeEvent_('drm-engine'); - - const startTime = Date.now() / 1000; - let firstEvent = true; - - this.drmEngine_ = this.createDrmEngine({ - netEngine: this.networkingEngine_, - onError: (e) => { - this.onError_(e); - }, - onKeyStatus: (map) => { - this.onKeyStatus_(map); - }, - onExpirationUpdated: (id, expiration) => { - this.onExpirationUpdated_(id, expiration); - }, - onEvent: (e) => { - this.dispatchEvent(e); - if (e.type == shaka.util.FakeEvent.EventName.DrmSessionUpdate && - firstEvent) { - firstEvent = false; - const now = Date.now() / 1000; - const delta = now - startTime; - this.stats_.setDrmTime(delta); - // LCEVC data by itself is not encrypted in DRM protected streams - // and can therefore be accessed and decoded as normal. However, - // the LCEVC decoder needs access to the VideoElement output in - // order to apply the enhancement. In DRM contexts where the - // browser CDM restricts access from our decoder, the enhancement - // cannot be applied and therefore the LCEVC output canvas is - // hidden accordingly. - if (this.lcevcDec_) { - this.lcevcDec_.hideCanvas(); - } - } - }, - }); - - this.drmEngine_.configure(this.config_.drm); + 'We should have a media element when initializing media source.'); + goog.asserts.assert( + this.mediaSourceEngine_ == null, + 'We should not have a media source engine yet.'); - const tracksChanged = shaka.util.StreamUtils.applyRestrictions( - this.manifest_.variants, this.config_.restrictions, this.maxHwRes_); - if (tracksChanged && this.streamingEngine_) { - this.onTracksChanged_(); - } + this.makeStateChangeEvent_('media-source'); - const playableVariants = shaka.util.StreamUtils.getPlayableVariants( - this.manifest_.variants); + // When changing text visibility we need to update both the text displayer + // and streaming engine because we don't always stream text. To ensure + // that the text displayer and streaming engine are always in sync, wait + // until they are both initialized before setting the initial value. + const textDisplayerFactory = this.config_.textDisplayFactory; + const textDisplayer = textDisplayerFactory(); + this.lastTextFactory_ = textDisplayerFactory; - await this.drmEngine_.initForPlayback( - playableVariants, - this.manifest_.offlineSessionIds); + const mediaSourceEngine = this.createMediaSourceEngine( + this.video_, + textDisplayer, + (metadata, offset, endTime) => { + this.processTimedMetadataMediaSrc_(metadata, offset, endTime); + }, + this.lcevcDec_); + mediaSourceEngine.configure(this.config_.mediaSource); + const {segmentRelativeVttTiming} = this.config_.manifest; + mediaSourceEngine.setSegmentRelativeVttTiming(segmentRelativeVttTiming); - await this.drmEngine_.attach(this.video_); + // Wait for media source engine to finish opening. This promise should + // NEVER be rejected as per the media source engine implementation. + await mediaSourceEngine.open(); - // Now that we have drm information, filter the manifest (again) so that - // we can ensure we only use variants with the selected key system. - await this.filterManifest_(this.manifest_); + // Wait until it is ready to actually store the reference. + this.mediaSourceEngine_ = mediaSourceEngine; } /** * Starts loading the content described by the parsed manifest. * * @param {number} startTimeOfLoad + * @param {?shaka.extern.Variant} prefetchedVariant + * @param {!Map.} segmentPrefetchById * @return {!Promise} * @private */ - async loadInner_(startTimeOfLoad) { + async loadInner_(startTimeOfLoad, prefetchedVariant, segmentPrefetchById) { goog.asserts.assert( this.video_, 'We should have a media element by now.'); goog.asserts.assert( this.manifest_, 'The manifest should already be parsed.'); goog.asserts.assert( this.assetUri_, 'We should have an asset uri by now.'); + goog.asserts.assert( + this.abrManager_, 'We should have an abr manager by now.'); this.makeStateChangeEvent_('load'); @@ -1856,46 +2063,6 @@ shaka.Player = class extends shaka.util.FakeEventTarget { // depending on the config. this.setupLcevc_(this.config_); - const abrFactory = this.config_.abrFactory; - if (!this.abrManager_ || this.abrManagerFactory_ != abrFactory) { - this.abrManagerFactory_ = abrFactory; - this.abrManager_ = abrFactory(); - if (typeof this.abrManager_.setMediaElement != 'function') { - shaka.Deprecate.deprecateFeature(5, - 'AbrManager', - 'Please use an AbrManager with setMediaElement function.'); - this.abrManager_.setMediaElement = () => {}; - } - if (typeof this.abrManager_.setCmsdManager != 'function') { - shaka.Deprecate.deprecateFeature(5, - 'AbrManager', - 'Please use an AbrManager with setCmsdManager function.'); - this.abrManager_.setCmsdManager = () => {}; - } - if (typeof this.abrManager_.trySuggestStreams != 'function') { - shaka.Deprecate.deprecateFeature(5, - 'AbrManager', - 'Please use an AbrManager with trySuggestStreams function.'); - this.abrManager_.trySuggestStreams = () => {}; - } - this.abrManager_.configure(this.config_.abr); - } - - // Copy preferred languages from the config again, in case the config was - // changed between construction and playback. - this.currentAdaptationSetCriteria_ = - new shaka.media.PreferenceBasedCriteria( - this.config_.preferredAudioLanguage, - this.config_.preferredVariantRole, - this.config_.preferredAudioChannelCount, - this.config_.preferredVideoHdrLevel, - this.config_.preferSpatialAudio, - this.config_.preferredVideoLayout, - this.config_.preferredAudioLabel, - this.config_.preferredVideoLabel, - this.config_.mediaSource.codecSwitchingStrategy, - this.config_.manifest.dash.enableAudioGroups); - this.currentTextLanguage_ = this.config_.preferredTextLanguage; this.currentTextRole_ = this.config_.preferredTextRole; this.currentTextForced_ = this.config_.preferForcedSubs; @@ -1910,14 +2077,6 @@ shaka.Player = class extends shaka.util.FakeEventTarget { this.abrManager_.setMediaElement(mediaElement); this.abrManager_.setCmsdManager(this.cmsdManager_); - // If the content is multi-codec and the browser can play more than one of - // them, choose codecs now before we initialize streaming. - shaka.util.StreamUtils.chooseCodecsAndFilterManifest( - this.manifest_, - this.config_.preferredVideoCodecs, - this.config_.preferredAudioCodecs, - this.config_.preferredDecodingAttributes); - this.streamingEngine_ = this.createStreamingEngine(); this.streamingEngine_.configure(this.config_.streaming); @@ -1948,15 +2107,15 @@ shaka.Player = class extends shaka.util.FakeEventTarget { // The event must be fired after we filter by restrictions but before the // active stream is picked to allow those listening for the "streaming" // event to make changes before streaming starts. - this.dispatchEvent( - this.makeEvent_(shaka.util.FakeEvent.EventName.Streaming)); + this.dispatchEvent(shaka.Player.makeEvent_( + shaka.util.FakeEvent.EventName.Streaming)); // Pick the initial streams to play. // Unless the user has already picked a variant, anyway, by calling // selectVariantTrack before this loading stage. - let initialVariant = null; + let initialVariant = prefetchedVariant; const activeVariant = this.streamingEngine_.getCurrentVariant(); - if (!activeVariant) { + if (!activeVariant && !initialVariant) { initialVariant = this.chooseVariant_(/* initialSelection= */ true); goog.asserts.assert(initialVariant, 'Must choose an initial variant!'); } @@ -2037,7 +2196,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget { // Start streaming content. This will start the flow of content down to // media source. - await this.streamingEngine_.start(); + await this.streamingEngine_.start(segmentPrefetchById); if (this.config_.abr.enabled) { this.abrManager_.enable(); @@ -2118,10 +2277,13 @@ shaka.Player = class extends shaka.util.FakeEventTarget { this.onError_(e); }, onKeyStatus: (map) => { - this.onKeyStatus_(map); + // According to this.onKeyStatus_, we can't even use this information + // in src= mode, so this is just a no-op. }, onExpirationUpdated: (id, expiration) => { - this.onExpirationUpdated_(id, expiration); + const event = shaka.Player.makeEvent_( + shaka.util.FakeEvent.EventName.ExpirationUpdated); + this.dispatchEvent(event); }, onEvent: (e) => { this.dispatchEvent(e); @@ -2326,8 +2488,8 @@ shaka.Player = class extends shaka.util.FakeEventTarget { // The event doesn't mean as much for src= playback, since we don't // control streaming. But we should fire it in this path anyway since // some applications may be expecting it as a life-cycle event. - this.dispatchEvent( - this.makeEvent_(shaka.util.FakeEvent.EventName.Streaming)); + this.dispatchEvent(shaka.Player.makeEvent_( + shaka.util.FakeEvent.EventName.Streaming)); // The "load" Promise is resolved when we have loaded the metadata. If we // wait for the full data, that won't happen on Safari until the play @@ -2561,7 +2723,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget { .set('endTime', endTime) .set('metadataType', metadataType) .set('payload', payload); - this.dispatchEvent(this.makeEvent_(eventName, data)); + this.dispatchEvent(shaka.Player.makeEvent_(eventName, data)); } /** @@ -2591,35 +2753,6 @@ shaka.Player = class extends shaka.util.FakeEventTarget { }); } - /** - * Take a series of variants and ensure that they only contain one type of - * variant. The different options are: - * 1. Audio-Video - * 2. Audio-Only - * 3. Video-Only - * - * A manifest can only contain a single type because once we initialize media - * source to expect specific streams, it must always have content for those - * streams. If we were to start with audio+video and switch to an audio-only - * variant, media source would block waiting for video content. - * - * @param {shaka.extern.Manifest} manifest - * @private - */ - static filterForAVVariants_(manifest) { - const isAVVariant = (variant) => { - // Audio-video variants may include both streams separately or may be - // single multiplexed streams with multiple codecs. - return (variant.video && variant.audio) || - (variant.video && variant.video.codecs.includes(',')); - }; - if (manifest.variants.some(isAVVariant)) { - shaka.log.debug('Found variant with audio and video content, ' + - 'so filtering out audio-only content.'); - manifest.variants = manifest.variants.filter(isAVVariant); - } - } - /** * Releases all of the mutexes of the player. Meant for use by the tests. * @export @@ -2637,25 +2770,57 @@ shaka.Player = class extends shaka.util.FakeEventTarget { * @return {!shaka.media.DrmEngine} */ createDrmEngine(playerInterface) { - const updateExpirationTime = this.config_.drm.updateExpirationTime; - return new shaka.media.DrmEngine(playerInterface, updateExpirationTime); + return new shaka.media.DrmEngine(playerInterface); } /** * Creates a new instance of NetworkingEngine. This can be replaced by tests * to create fake instances instead. * + * @param {(function():?shaka.media.PreloadManager)=} getPreloadManager * @return {!shaka.net.NetworkingEngine} */ - createNetworkingEngine() { + createNetworkingEngine(getPreloadManager) { + if (!getPreloadManager) { + getPreloadManager = () => null; + } + + const getAbrManager = () => { + if (getPreloadManager()) { + return getPreloadManager().getAbrManager(); + } else { + return this.abrManager_; + } + }; + const getParser = () => { + if (getPreloadManager()) { + return getPreloadManager().getParser(); + } else { + return this.parser_; + } + }; + const lateQueue = (fn) => { + if (getPreloadManager()) { + getPreloadManager().addQueuedOperation(true, fn); + } else { + fn(); + } + }; + const dispatchEvent = (event) => { + if (getPreloadManager()) { + getPreloadManager().dispatchEvent(event); + } else { + this.dispatchEvent(event); + } + }; /** @type {function(number, number, boolean)} */ const onProgressUpdated_ = (deltaTimeMs, bytesDownloaded, allowSwitch) => { // In some situations, such as during offline storage, the abr manager // might not yet exist. Therefore, we need to check if abr manager has // been initialized before using it. - if (this.abrManager_) { - this.abrManager_.segmentDownloaded( - deltaTimeMs, bytesDownloaded, allowSwitch); + const abrManager = getAbrManager(); + if (abrManager) { + abrManager.segmentDownloaded(deltaTimeMs, bytesDownloaded, allowSwitch); } }; /** @type {shaka.net.NetworkingEngine.OnHeadersReceived} */ @@ -2666,10 +2831,12 @@ shaka.Player = class extends shaka.util.FakeEventTarget { .set('headers', headers) .set('request', request) .set('requestType', requestType); - this.dispatchEvent(this.makeEvent_(name, data)); - if (this.cmsdManager_) { - this.cmsdManager_.processHeaders(headers); - } + dispatchEvent(shaka.Player.makeEvent_(name, data)); + lateQueue(() => { + if (this.cmsdManager_) { + this.cmsdManager_.processHeaders(headers); + } + }); }; /** @type {shaka.net.NetworkingEngine.OnDownloadFailed} */ const onDownloadFailed_ = (request, error, httpResponseCode, aborted) => { @@ -2680,17 +2847,19 @@ shaka.Player = class extends shaka.util.FakeEventTarget { .set('error', error) .set('httpResponseCode', httpResponseCode) .set('aborted', aborted); - this.dispatchEvent(this.makeEvent_(name, data)); + dispatchEvent(shaka.Player.makeEvent_(name, data)); }; /** @type {shaka.net.NetworkingEngine.OnRequest} */ const onRequest_ = (type, request, context) => { - this.cmcdManager_.applyData(type, request, context); + lateQueue(() => { + this.cmcdManager_.applyData(type, request, context); + }); }; - const onRetry_ = (type, context, newUrl, oldUrl) => { - if (this.parser_ && this.parser_.banLocation) { - this.parser_.banLocation(oldUrl); + const parser = getParser(); + if (parser && parser.banLocation) { + parser.banLocation(oldUrl); } }; @@ -3075,6 +3244,8 @@ shaka.Player = class extends shaka.util.FakeEventTarget { * @private */ applyConfig_() { + this.manifestFilterer_ = new shaka.media.ManifestFilterer( + this.config_, this.maxHwRes_, this.drmEngine_); if (this.parser_) { const manifestConfig = shaka.util.ObjectUtils.cloneObject(this.config_.manifest); @@ -3091,9 +3262,14 @@ shaka.Player = class extends shaka.util.FakeEventTarget { this.streamingEngine_.configure(this.config_.streaming); // Need to apply the restrictions. + // this.filterManifestWithRestrictions_() may throw. try { - // this.filterManifestWithRestrictions_() may throw. - this.filterManifestWithRestrictions_(this.manifest_); + if (this.loadMode_ != shaka.Player.LoadMode.DESTROYED) { + if (this.manifestFilterer_.filterManifestWithRestrictions( + this.manifest_)) { + this.onTracksChanged_(); + } + } } catch (error) { this.onError_(error); } @@ -3402,24 +3578,6 @@ shaka.Player = class extends shaka.util.FakeEventTarget { } } - /** - * Return the value of lowLatencyMode configuration. - * @return {boolean} - * @private - */ - isLowLatencyMode_() { - return this.config_.streaming.lowLatencyMode; - } - - /** - * Return the value of autoLowLatencyMode configuration. - * @return {boolean} - * @private - */ - isAutoLowLatencyMode_() { - return this.config_.streaming.autoLowLatencyMode; - } - /** * Get the range of time (in seconds) that seeking is allowed. If the player * has not loaded content and the manifest is HLS, this will return a range @@ -5210,25 +5368,6 @@ shaka.Player = class extends shaka.util.FakeEventTarget { this.maxHwRes_.height = height; } - /** - * Detect and set the maximum resolution that the platform's hardware can - * handle. - * - * @private - */ - async detectAndSetMaxHardwareResolution_() { - // Avoid having to detect the resolution again if it has already been - // detected or set - if (this.maxHwRes_.width != Infinity || - this.maxHwRes_.height != Infinity) { - return; - } - const maxResolution = - await shaka.util.Platform.detectMaxHardwareResolution(); - this.maxHwRes_.width = maxResolution.width; - this.maxHwRes_.height = maxResolution.height; - } - /** * Retry streaming after a streaming failure has occurred. When the player has * not loaded content or is loading content, this will be a no-op and will @@ -5446,82 +5585,6 @@ shaka.Player = class extends shaka.util.FakeEventTarget { } } - /** - * Filters a manifest, removing unplayable streams/variants. - * - * @param {?shaka.extern.Manifest} manifest - * @private - */ - async filterManifest_(manifest) { - await this.filterManifestWithStreamUtils_(manifest); - this.filterManifestWithRestrictions_(manifest); - } - - /** - * Filters a manifest, removing unplayable streams/variants. - * - * @param {?shaka.extern.Manifest} manifest - * @private - */ - async filterManifestWithStreamUtils_(manifest) { - goog.asserts.assert(manifest, 'Manifest should exist!'); - await shaka.util.StreamUtils.filterManifest(this.drmEngine_, manifest); - this.checkPlayableVariants_(manifest); - } - - - /** - * Apply the restrictions configuration to the manifest, and check if there's - * a variant that meets the restrictions. - * - * @param {?shaka.extern.Manifest} manifest - * @private - */ - filterManifestWithRestrictions_(manifest) { - // Return if |destroy| is called. - if (this.loadMode_ == shaka.Player.LoadMode.DESTROYED) { - return; - } - const tracksChanged = shaka.util.StreamUtils.applyRestrictions( - manifest.variants, this.config_.restrictions, this.maxHwRes_); - if (tracksChanged && this.streamingEngine_) { - this.onTracksChanged_(); - } - - // We may need to create new sessions for any new init data. - const currentDrmInfo = - this.drmEngine_ ? this.drmEngine_.getDrmInfo() : null; - // DrmEngine.newInitData() requires mediaKeys to be available. - if (currentDrmInfo && this.drmEngine_.getMediaKeys()) { - for (const variant of manifest.variants) { - this.processDrmInfos_(currentDrmInfo.keySystem, variant.video); - this.processDrmInfos_(currentDrmInfo.keySystem, variant.audio); - } - } - this.checkRestrictedVariants_(manifest); - } - - /** - * @param {string} keySystem - * @param {?shaka.extern.Stream} stream - * @private - */ - processDrmInfos_(keySystem, stream) { - if (!stream) { - return; - } - - for (const drmInfo of stream.drmInfos) { - // Ignore any data for different key systems. - if (drmInfo.keySystem == keySystem) { - for (const initData of (drmInfo.initData || [])) { - this.drmEngine_.newInitData( - initData.initDataType, initData.initData); - } - } - } - } - /** * @param {shaka.extern.Variant} initialVariant * @param {number} time @@ -5600,7 +5663,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget { // buffering. const eventName = shaka.util.FakeEvent.EventName.Buffering; const data = (new Map()).set('buffering', isBuffering); - this.dispatchEvent(this.makeEvent_(eventName, data)); + this.dispatchEvent(shaka.Player.makeEvent_(eventName, data)); } /** @@ -5633,7 +5696,8 @@ shaka.Player = class extends shaka.util.FakeEventTarget { this.playRateController_.set(newRate); } - const event = this.makeEvent_(shaka.util.FakeEvent.EventName.RateChange); + const event = shaka.Player.makeEvent_( + shaka.util.FakeEvent.EventName.RateChange); this.dispatchEvent(event); } @@ -5669,7 +5733,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget { if (stateChanged) { const eventName = shaka.util.FakeEvent.EventName.StateChanged; const data = (new Map()).set('newstate', updateState); - this.dispatchEvent(this.makeEvent_(eventName, data)); + this.dispatchEvent(shaka.Player.makeEvent_(eventName, data)); } } @@ -5832,15 +5896,19 @@ shaka.Player = class extends shaka.util.FakeEventTarget { if (hasNewCompletionPercent) { let event; if (this.completionPercent_ == 0) { - event = this.makeEvent_(shaka.util.FakeEvent.EventName.Started); + event = shaka.Player.makeEvent_(shaka.util.FakeEvent.EventName.Started); } else if (this.completionPercent_ == 25) { - event = this.makeEvent_(shaka.util.FakeEvent.EventName.FirstQuartile); + event = shaka.Player.makeEvent_( + shaka.util.FakeEvent.EventName.FirstQuartile); } else if (this.completionPercent_ == 50) { - event = this.makeEvent_(shaka.util.FakeEvent.EventName.Midpoint); + event = shaka.Player.makeEvent_( + shaka.util.FakeEvent.EventName.Midpoint); } else if (this.completionPercent_ == 75) { - event = this.makeEvent_(shaka.util.FakeEvent.EventName.ThirdQuartile); + event = shaka.Player.makeEvent_( + shaka.util.FakeEvent.EventName.ThirdQuartile); } else if (this.completionPercent_ == 100) { - event = this.makeEvent_(shaka.util.FakeEvent.EventName.Complete); + event = shaka.Player.makeEvent_( + shaka.util.FakeEvent.EventName.Complete); } if (event) { this.dispatchEvent(event); @@ -5880,7 +5948,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget { updateAbrManagerVariants_() { try { goog.asserts.assert(this.manifest_, 'Manifest should exist by now!'); - this.checkRestrictedVariants_(this.manifest_); + this.manifestFilterer_.checkRestrictedVariants(this.manifest_); } catch (e) { this.onError_(e); return false; @@ -6197,7 +6265,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget { .set('start', start) .set('end', end) .set('contentType', contentType); - this.dispatchEvent(this.makeEvent_( + this.dispatchEvent(shaka.Player.makeEvent_( shaka.util.FakeEvent.EventName.SegmentAppended, data)); } @@ -6247,8 +6315,8 @@ shaka.Player = class extends shaka.util.FakeEventTarget { if (this.lcevcDec_) { this.lcevcDec_.updateVariant(to, this.getManifestType()); } - const event = - this.makeEvent_(shaka.util.FakeEvent.EventName.Adaptation, data); + const event = shaka.Player.makeEvent_( + shaka.util.FakeEvent.EventName.Adaptation, data); this.delayDispatchEvent_(event); } @@ -6259,7 +6327,8 @@ shaka.Player = class extends shaka.util.FakeEventTarget { onTracksChanged_() { // Delay the 'trackschanged' event so StreamingEngine has time to absorb the // changes before the user tries to query it. - const event = this.makeEvent_(shaka.util.FakeEvent.EventName.TracksChanged); + const event = shaka.Player.makeEvent_( + shaka.util.FakeEvent.EventName.TracksChanged); this.delayDispatchEvent_(event); } @@ -6279,8 +6348,8 @@ shaka.Player = class extends shaka.util.FakeEventTarget { this.lcevcDec_.updateVariant(to, this.getManifestType()); } - const event = - this.makeEvent_(shaka.util.FakeEvent.EventName.VariantChanged, data); + const event = shaka.Player.makeEvent_( + shaka.util.FakeEvent.EventName.VariantChanged, data); this.delayDispatchEvent_(event); } @@ -6291,14 +6360,15 @@ shaka.Player = class extends shaka.util.FakeEventTarget { onTextChanged_() { // Delay the 'textchanged' event so StreamingEngine time to absorb the // changes before the user tries to query it. - const event = this.makeEvent_(shaka.util.FakeEvent.EventName.TextChanged); + const event = shaka.Player.makeEvent_( + shaka.util.FakeEvent.EventName.TextChanged); this.delayDispatchEvent_(event); } /** @private */ onTextTrackVisibility_() { - const event = - this.makeEvent_(shaka.util.FakeEvent.EventName.TextTrackVisibility); + const event = shaka.Player.makeEvent_( + shaka.util.FakeEvent.EventName.TextTrackVisibility); this.delayDispatchEvent_(event); } @@ -6310,7 +6380,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget { } const data = (new Map()).set('newStatus', this.config_.abr.enabled); - this.delayDispatchEvent_(this.makeEvent_( + this.delayDispatchEvent_(shaka.Player.makeEvent_( shaka.util.FakeEvent.EventName.AbrStatusChanged, data)); } @@ -6444,7 +6514,8 @@ shaka.Player = class extends shaka.util.FakeEventTarget { } const eventName = shaka.util.FakeEvent.EventName.Error; - const event = this.makeEvent_(eventName, (new Map()).set('detail', error)); + const event = shaka.Player.makeEvent_( + eventName, (new Map()).set('detail', error)); this.dispatchEvent(event); if (event.defaultPrevented) { error.handled = true; @@ -6459,10 +6530,11 @@ shaka.Player = class extends shaka.util.FakeEventTarget { * * @param {!shaka.util.FakeEvent.EventName} eventName * @param {shaka.extern.TimelineRegionInfo} region + * @param {shaka.util.FakeEventTarget=} eventTarget * * @private */ - onRegionEvent_(eventName, region) { + onRegionEvent_(eventName, region, eventTarget = this) { // Always make a copy to avoid exposing our internal data to the app. const clone = { schemeIdUri: region.schemeIdUri, @@ -6474,7 +6546,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget { }; const data = (new Map()).set('detail', clone); - this.dispatchEvent(this.makeEvent_(eventName, data)); + eventTarget.dispatchEvent(shaka.Player.makeEvent_(eventName, data)); } /** @@ -6505,7 +6577,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget { .set('mediaQuality', clone) .set('position', position); - this.dispatchEvent(this.makeEvent_( + this.dispatchEvent(shaka.Player.makeEvent_( shaka.util.FakeEvent.EventName.MediaQualityChanged, data)); } @@ -6568,14 +6640,10 @@ shaka.Player = class extends shaka.util.FakeEventTarget { * @private */ onKeyStatus_(keyStatusMap) { - if (!this.streamingEngine_) { - // We can't use this info to manage restrictions in src= mode, so ignore - // it. - return; - } + goog.asserts.assert(this.streamingEngine_, 'Cannot be called in src= mode'); - const event = - this.makeEvent_(shaka.util.FakeEvent.EventName.KeyStatusChanged); + const event = shaka.Player.makeEvent_( + shaka.util.FakeEvent.EventName.KeyStatusChanged); this.dispatchEvent(event); const keyIds = Object.keys(keyStatusMap); @@ -6597,7 +6665,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget { 'restrictions so we don\'t select those tracks.'); } - const restrictedStatuses = shaka.Player.restrictedStatuses_; + const restrictedStatuses = shaka.media.ManifestFilterer.restrictedStatuses; let tracksChanged = false; goog.asserts.assert(this.drmEngine_, 'drmEngine should be non-null here.'); @@ -6646,22 +6714,6 @@ shaka.Player = class extends shaka.util.FakeEventTarget { } } - /** - * Callback from DrmEngine - * @param {string} keyId - * @param {number} expiration - * @private - */ - onExpirationUpdated_(keyId, expiration) { - if (this.parser_ && this.parser_.onExpirationUpdated) { - this.parser_.onExpirationUpdated(keyId, expiration); - } - - const event = - this.makeEvent_(shaka.util.FakeEvent.EventName.ExpirationUpdated); - this.dispatchEvent(event); - } - /** * @return {boolean} true if we should stream text right now. * @private @@ -6705,93 +6757,6 @@ shaka.Player = class extends shaka.util.FakeEventTarget { } } - /** - * Checks if the variants are all restricted, and throw an appropriate - * exception if so. - * - * @param {shaka.extern.Manifest} manifest - * - * @private - */ - checkRestrictedVariants_(manifest) { - const restrictedStatuses = shaka.Player.restrictedStatuses_; - const keyStatusMap = - this.drmEngine_ ? this.drmEngine_.getKeyStatuses() : {}; - const keyIds = Object.keys(keyStatusMap); - const isGlobalStatus = keyIds.length && keyIds[0] == '00'; - - let hasPlayable = false; - let hasAppRestrictions = false; - - /** @type {!Set.} */ - const missingKeys = new Set(); - - /** @type {!Set.} */ - const badKeyStatuses = new Set(); - - for (const variant of manifest.variants) { - // TODO: Combine with onKeyStatus_. - const streams = []; - if (variant.audio) { - streams.push(variant.audio); - } - if (variant.video) { - streams.push(variant.video); - } - - for (const stream of streams) { - if (stream.keyIds.size) { - for (const keyId of stream.keyIds) { - const keyStatus = keyStatusMap[isGlobalStatus ? '00' : keyId]; - if (!keyStatus) { - missingKeys.add(keyId); - } else if (restrictedStatuses.includes(keyStatus)) { - badKeyStatuses.add(keyStatus); - } - } - } // if (stream.keyIds.size) - } - - if (!variant.allowedByApplication) { - hasAppRestrictions = true; - } else if (variant.allowedByKeySystem) { - hasPlayable = true; - } - } - - if (!hasPlayable) { - /** @type {shaka.extern.RestrictionInfo} */ - const data = { - hasAppRestrictions, - missingKeys: Array.from(missingKeys), - restrictedKeyStatuses: Array.from(badKeyStatuses), - }; - throw new shaka.util.Error( - shaka.util.Error.Severity.CRITICAL, - shaka.util.Error.Category.MANIFEST, - shaka.util.Error.Code.RESTRICTIONS_CANNOT_BE_MET, - data); - } - } - - /** - * Confirm some variants are playable. Otherwise, throw an exception. - * @param {!shaka.extern.Manifest} manifest - * @private - */ - checkPlayableVariants_(manifest) { - const valid = manifest.variants.some(shaka.util.StreamUtils.isPlayable); - - // If none of the variants are playable, throw - // CONTENT_UNSUPPORTED_BY_BROWSER. - if (!valid) { - throw new shaka.util.Error( - shaka.util.Error.Severity.CRITICAL, - shaka.util.Error.Category.MANIFEST, - shaka.util.Error.Code.CONTENT_UNSUPPORTED_BY_BROWSER); - } - } - /** * Fire an event, but wait a little bit so that the immediate execution can * complete before the event is handled. @@ -7031,18 +6996,6 @@ shaka.Player.version = 'v4.7.0' + '-uncompiled'; // x-release-please-version shaka.Deprecate.init(shaka.Player.version); -/** - * These are the EME key statuses that represent restricted playback. - * 'usable', 'released', 'output-downscaled', 'status-pending' are statuses - * of the usable keys. 'expired' status is being handled separately in - * DrmEngine. - * - * @const {!Array.} - * @private - */ -shaka.Player.restrictedStatuses_ = ['output-restricted', 'internal-error']; - - /** @private {!Object.} */ shaka.Player.supportPlugins_ = {}; diff --git a/lib/util/error.js b/lib/util/error.js index 53aa24c0b8..126fbc7992 100644 --- a/lib/util/error.js +++ b/lib/util/error.js @@ -945,6 +945,11 @@ shaka.util.Error.Code = { */ 'CONTENT_NOT_LOADED': 7004, + /** + * The call to preload failed, due to being called on src= content. + */ + 'SRC_EQUALS_PRELOAD_NOT_SUPPORTED': 7005, + /** * The Cast API is unavailable. This may be because of one of the following: * 1. The browser may not have Cast support diff --git a/test/cast/cast_utils_unit.js b/test/cast/cast_utils_unit.js index 93de562b8f..9ce797bd86 100644 --- a/test/cast/cast_utils_unit.js +++ b/test/cast/cast_utils_unit.js @@ -28,6 +28,7 @@ describe('CastUtils', () => { 'setVideoContainer', 'getActiveSessionsMetadata', 'releaseAllMutexes', // Very specific to the inner workings of the player. + 'preload', // Test helper methods (not @export'd) 'createDrmEngine', diff --git a/test/player_integration.js b/test/player_integration.js index b90ea89f74..7c8c9aa902 100644 --- a/test/player_integration.js +++ b/test/player_integration.js @@ -1374,4 +1374,12 @@ describe('Player', () => { expect(thumbnails.length).toBe(3); }); }); // describe('addThumbnailsTrack') + + it('preload', async () => { + const preloadManager = await player.preload('test:sintel_compiled'); + await preloadManager.waitForFinish(); + await player.load(preloadManager); + await video.play(); + await waiter.waitUntilPlayheadReachesOrFailOnTimeout(video, 1, 10); + }); }); diff --git a/test/player_load_graph_integration.js b/test/player_load_graph_integration.js index ec512f70d5..27be9657dc 100644 --- a/test/player_load_graph_integration.js +++ b/test/player_load_graph_integration.js @@ -9,6 +9,8 @@ describe('Player Load Graph', () => { /** @type {!HTMLVideoElement} */ let video; + /** @type {!HTMLVideoElement} */ + let video2; /** @type {shaka.Player} */ let player; @@ -21,10 +23,13 @@ describe('Player Load Graph', () => { beforeAll(() => { video = shaka.test.UiUtils.createVideoElement(); document.body.appendChild(video); + video2 = shaka.test.UiUtils.createVideoElement(); + document.body.appendChild(video2); }); afterAll(() => { document.body.removeChild(video); + document.body.removeChild(video2); }); beforeEach(() => { @@ -143,18 +148,18 @@ describe('Player Load Graph', () => { // Load 2 'unload', - 'media-source', 'manifest-parser', 'manifest', 'drm-engine', + 'media-source', 'load', // Load 3 'unload', - 'media-source', 'manifest-parser', 'manifest', 'drm-engine', + 'media-source', 'load', ]); }); @@ -508,12 +513,12 @@ describe('Player Load Graph', () => { it('goes from media source to attach', async () => { await startIn('media-source'); - await goTo('attach'); + await goTo('attach', video2); }); it('goes from media source to media source', async () => { await startIn('media-source'); - await goTo('media-source', 'attach'); // doesn't remake media source + await goTo('media-source', video2); }); it('goes from media source to load', async () => { @@ -533,12 +538,12 @@ describe('Player Load Graph', () => { it('goes from load to attach', async () => { await startIn('load'); - await goTo('attach'); + await goTo('attach', video2); }); it('goes from load to media source', async () => { await startIn('load'); - await goTo('media-source', 'attach'); // doesn't remake media source + await goTo('media-source', video2); }); it('goes from load to load', async () => { @@ -558,7 +563,7 @@ describe('Player Load Graph', () => { it('goes from src equals to attach', async () => { await startIn('src-equals'); - await goTo('attach'); + await goTo('attach', video2); }); it('goes from src equals to media source', async () => { @@ -584,13 +589,13 @@ describe('Player Load Graph', () => { it('goes from manifest parser to attach', async () => { await passingThrough('manifest-parser', () => { - return goTo('attach'); + return goTo('attach', video2); }); }); it('goes from manifest parser to media source', async () => { await passingThrough('manifest-parser', () => { - return goTo('media-source', 'attach'); // doesn't remake media source + return goTo('media-source', video2); }); }); @@ -614,13 +619,13 @@ describe('Player Load Graph', () => { it('goes from manifest to attach', async () => { await passingThrough('manifest', () => { - return goTo('attach'); + return goTo('attach', video2); }); }); it('goes from manifest to media source', async () => { await passingThrough('manifest', () => { - return goTo('media-source', 'attach'); // doesn't remake media source + return goTo('media-source', video2); }); }); @@ -644,13 +649,13 @@ describe('Player Load Graph', () => { it('goes from drm engine to attach', async () => { await passingThrough('drm-engine', () => { - return goTo('attach'); + return goTo('attach', video2); }); }); it('goes from drm engine to media source', async () => { await passingThrough('drm-engine', () => { - return goTo('media-source', 'attach'); // doesn't remake media source + return goTo('media-source', video2); }); }); @@ -674,7 +679,7 @@ describe('Player Load Graph', () => { it('goes from unload to attach', async () => { await passingThrough('unload', () => { - return goTo('attach'); + return goTo('attach', video2); }); }); @@ -797,20 +802,22 @@ describe('Player Load Graph', () => { * starting the state change. * * @param {string} state - * @param {string=} expectedState + * @param {HTMLVideoElement=} videoToUse * @return {!Promise} */ - async function goTo(state, expectedState) { + async function goTo(state, videoToUse = video) { /** @type {!Map.} */ const actions = new Map() .set('detach', () => { return player.detach(); }) .set('attach', () => { - return player.attach(video, /* initMediaSource= */ false); + return player.attach( + videoToUse || video, /* initMediaSource= */ false); }) .set('media-source', () => { - return player.attach(video, /* initMediaSource= */ true); + return player.attach( + videoToUse || video, /* initMediaSource= */ true); }) .set('load', () => { return player.load('test:sintel'); @@ -822,7 +829,7 @@ describe('Player Load Graph', () => { const action = actions.get(state); expect(action).toBeTruthy(); await action(); - expect(lastStateChange).toBe(expectedState || state); + expect(lastStateChange).toBe(state); } }); diff --git a/test/player_unit.js b/test/player_unit.js index f83c561cf0..d1ee7b1f89 100644 --- a/test/player_unit.js +++ b/test/player_unit.js @@ -1232,6 +1232,16 @@ describe('Player', () => { }); }); + describe('preload', () => { + it('performs tasks during preload and not load', async () => { + const preloadManager = await player.preload( + fakeManifestUri, 0, fakeMimeType); + await preloadManager.waitForFinish(); + shaka.media.ManifestParser.registerParserByMime(fakeMimeType, fail); + await player.load(preloadManager); + }); + }); + describe('resetConfiguration', () => { it('resets configurations to default', () => { const default_ = player.getConfiguration().streaming.bufferingGoal; From 5b7d7b23168dcb3839d271e20756908206b12693 Mon Sep 17 00:00:00 2001 From: Joey Parrish Date: Tue, 6 Feb 2024 10:17:08 -0800 Subject: [PATCH 31/64] ci: Temporarily disable Edge on Windows in the lab (#6216) shaka-lab-hub reports: ``` /wd/hub/session java.io.IOException: org.openqa.grid.common.exception.GridException: Cannot extract a capabilities from the request: ``` Generally, there should be a request object after this, but here it is blank. It's not clear why or how this could be. There are no errors from shaka-lab-node on Windows. --- build/shaka-lab.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/build/shaka-lab.yaml b/build/shaka-lab.yaml index 16c2567604..72b5fc423d 100644 --- a/build/shaka-lab.yaml +++ b/build/shaka-lab.yaml @@ -161,6 +161,8 @@ FirefoxWindows: - *basic_firefox_config Edge: + # TODO(b/323916397): Edge on Windows not working currently + disabled: true browser: msedge os: Windows extra_configs: From 59451e6cb3b44c5a4786abb38e7f8a5cf2a87c1d Mon Sep 17 00:00:00 2001 From: Joey Parrish Date: Tue, 6 Feb 2024 10:53:05 -0800 Subject: [PATCH 32/64] ci: Restore Edge on Windows in the lab (#6220) By specifying the binary path and also merging https://github.com/shaka-project/shaka-lab/pull/47, we are able to restore Edge on Windows in the lab. --- build/shaka-lab.yaml | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/build/shaka-lab.yaml b/build/shaka-lab.yaml index 72b5fc423d..884fb8c32f 100644 --- a/build/shaka-lab.yaml +++ b/build/shaka-lab.yaml @@ -68,6 +68,18 @@ vars: ms:edgeOptions: binary: /usr/bin/microsoft-edge + # Work around https://github.com/MicrosoftEdge/EdgeWebDriver/issues/102#issuecomment-1710724173 + # by specifying the binary path on Mac. + edge_mac_config: &edge_mac_config + ms:edgeOptions: + binary: /Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge + + # Work around https://github.com/MicrosoftEdge/EdgeWebDriver/issues/102#issuecomment-1710724173 + # by specifying the binary path on Mac. + edge_windows_config: &edge_windows_config + ms:edgeOptions: + binary: "C:/Program Files (x86)/Microsoft/Edge/Application/msedge.exe" + android_chrome_config: &android_chrome_config goog:chromeOptions: args: @@ -132,6 +144,7 @@ EdgeMac: os: Mac extra_configs: - *basic_edge_config + - *edge_mac_config Safari: browser: safari @@ -161,12 +174,11 @@ FirefoxWindows: - *basic_firefox_config Edge: - # TODO(b/323916397): Edge on Windows not working currently - disabled: true browser: msedge os: Windows extra_configs: - *basic_edge_config + - *edge_windows_config ### Linux ### From 33a8c5760ced858ad8be297dfd5833917569f64e Mon Sep 17 00:00:00 2001 From: Joey Parrish Date: Tue, 6 Feb 2024 12:24:14 -0800 Subject: [PATCH 33/64] ci: Fix Edge launcher for local testing and GitHub CI (#6221) This updated version of karma-local-wd-launcher incorporates https://github.com/shaka-project/karma-local-wd-launcher/pull/65 to supply a path to the Edge binary on all platforms. This fixes local testing and GitHub CI testing of Edge. Though the tests run once more, there are still some test failures that need to be dealt with. --- package-lock.json | 14 +++++++------- package.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index a0addb00d5..909e105a39 100644 --- a/package-lock.json +++ b/package-lock.json @@ -44,7 +44,7 @@ "karma-coverage": "^2.2.0", "karma-jasmine": "^4.0.1", "karma-jasmine-ajax": "^0.1.13", - "karma-local-wd-launcher": "^1.6.6", + "karma-local-wd-launcher": "^1.6.7", "karma-opera-launcher": "^1.0.0", "karma-sourcemap-loader": "^0.3.8", "karma-spec-reporter": "^0.0.34", @@ -5627,9 +5627,9 @@ "dev": true }, "node_modules/karma-local-wd-launcher": { - "version": "1.6.6", - "resolved": "https://registry.npmjs.org/karma-local-wd-launcher/-/karma-local-wd-launcher-1.6.6.tgz", - "integrity": "sha512-8An620Xk5o6o0qVq0ATSgI2xY3+QAzEgrYvwoy4N0eDPzPrCOy99RYPCEOit8XL2AKeOCJ3Q7Puc+mjtBiVwpg==", + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/karma-local-wd-launcher/-/karma-local-wd-launcher-1.6.7.tgz", + "integrity": "sha512-rqGX9TRUzfzqnUHdFWhvAAy321n7iFe2FGHS3KVseRMWhD3Wz1bCfcL2jp9Y+/3tHSWovoIey98V1F4yH80POQ==", "dev": true, "dependencies": { "lodash": "^4.17.21", @@ -13040,9 +13040,9 @@ } }, "karma-local-wd-launcher": { - "version": "1.6.6", - "resolved": "https://registry.npmjs.org/karma-local-wd-launcher/-/karma-local-wd-launcher-1.6.6.tgz", - "integrity": "sha512-8An620Xk5o6o0qVq0ATSgI2xY3+QAzEgrYvwoy4N0eDPzPrCOy99RYPCEOit8XL2AKeOCJ3Q7Puc+mjtBiVwpg==", + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/karma-local-wd-launcher/-/karma-local-wd-launcher-1.6.7.tgz", + "integrity": "sha512-rqGX9TRUzfzqnUHdFWhvAAy321n7iFe2FGHS3KVseRMWhD3Wz1bCfcL2jp9Y+/3tHSWovoIey98V1F4yH80POQ==", "dev": true, "requires": { "lodash": "^4.17.21", diff --git a/package.json b/package.json index e9ddd5e549..bcd0ee2e7c 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,7 @@ "karma-coverage": "^2.2.0", "karma-jasmine": "^4.0.1", "karma-jasmine-ajax": "^0.1.13", - "karma-local-wd-launcher": "^1.6.6", + "karma-local-wd-launcher": "^1.6.7", "karma-opera-launcher": "^1.0.0", "karma-sourcemap-loader": "^0.3.8", "karma-spec-reporter": "^0.0.34", From 36b7367ebd3efafd6e46d8ef74758cd834aff224 Mon Sep 17 00:00:00 2001 From: theodab Date: Tue, 6 Feb 2024 12:27:11 -0800 Subject: [PATCH 34/64] fix(preload): Only start preload if manager exists (#6222) Also fixes how demo cards handle src= preloads. --- demo/asset_card.js | 8 ++++++-- lib/player.js | 3 ++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/demo/asset_card.js b/demo/asset_card.js index 89d57d9021..ff90e846f9 100644 --- a/demo/asset_card.js +++ b/demo/asset_card.js @@ -272,8 +272,12 @@ shakaDemo.AssetCard = class { try { await shakaDemoMain.preloadAsset(this.asset_); this.remakeButtons(); - await this.asset_.preloadManager.waitForFinish(); - this.asset_.preloaded = true; + if (this.asset_.preloadManager) { + await this.asset_.preloadManager.waitForFinish(); + this.asset_.preloaded = true; + } else { + this.asset_.preloadFailed = true; + } } catch (error) { this.asset_.preloadManager = null; this.asset_.preloadFailed = true; diff --git a/lib/player.js b/lib/player.js index 0d01a889c9..5ee0e44a8b 100644 --- a/lib/player.js +++ b/lib/player.js @@ -1627,8 +1627,9 @@ shaka.Player = class extends shaka.util.FakeEventTarget { shaka.util.Error.Severity.CRITICAL, shaka.util.Error.Category.PLAYER, shaka.util.Error.Code.SRC_EQUALS_PRELOAD_NOT_SUPPORTED)); + } else { + preloadManager.start().catch((error) => {}); // Catch errors. } - preloadManager.start().catch((error) => {}); // Catch errors. return preloadManager; } From 4dc8401dd4c3e655969b6d563346549dbdd23ea6 Mon Sep 17 00:00:00 2001 From: Joey Parrish Date: Thu, 8 Feb 2024 09:34:56 -0800 Subject: [PATCH 35/64] test: Fix flaky test for BufferingObserver (#6235) This adds a mock for Date.now. Any test using Date needs to have Date mocked to avoid flake. Closes #6226 --- test/media/buffering_observer_unit.js | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/test/media/buffering_observer_unit.js b/test/media/buffering_observer_unit.js index 0f8bfa2e75..286a895ad5 100644 --- a/test/media/buffering_observer_unit.js +++ b/test/media/buffering_observer_unit.js @@ -11,15 +11,28 @@ describe('BufferingObserver', () => { const thresholdAfterStarving = 5; const thresholdAfterSatisfied = 2; + const originalDateNow = Date.now; + + /** @type {!Date} */ + let baseTime; + /** @type {!shaka.media.BufferingObserver} */ let controller; beforeEach(() => { + // Any test using Date needs to have Date mocked to avoid flake. + baseTime = new Date(2015, 11, 30); + Date.now = () => baseTime.getTime(); + controller = new BufferingObserver( thresholdAfterStarving, thresholdAfterSatisfied); }); + afterEach(() => { + Date.now = originalDateNow; + }); + describe('when satisfied', () => { beforeEach(() => { controller.setState(State.SATISFIED); From 83c02b8a5cfe48e2c028efb3aca6d3fd9026b062 Mon Sep 17 00:00:00 2001 From: Joey Parrish Date: Thu, 8 Feb 2024 09:35:21 -0800 Subject: [PATCH 36/64] test: Fix seek range test flake on Safari (#6237) Closes #6227 --- test/test/util/waiter.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/test/util/waiter.js b/test/test/util/waiter.js index 7351b3bc2d..5416021d71 100644 --- a/test/test/util/waiter.js +++ b/test/test/util/waiter.js @@ -184,6 +184,7 @@ shaka.test.Waiter = class { } this.eventManager_.unlisten(mediaElement, 'timeupdate'); this.eventManager_.unlisten(mediaElement, 'ended'); + this.eventManager_.unlisten(mediaElement, 'durationchange'); }; const p = new Promise((resolve) => { @@ -202,6 +203,10 @@ shaka.test.Waiter = class { timer.tickEvery(/* seconds= */ 1); this.eventManager_.listen(mediaElement, 'timeupdate', check); this.eventManager_.listen(mediaElement, 'ended', check); + // Some tests on Safari expose a condition where the ended flag can be + // found in the desired state in a brief window during a durationchange + // event. + this.eventManager_.listen(mediaElement, 'durationchange', check); }); return this.waitUntilGeneric_(goalName, p, cleanup, mediaElement); From 93d616e9543b0c54f8b65695e713b9f710d1623b Mon Sep 17 00:00:00 2001 From: Julian Domingo Date: Mon, 12 Feb 2024 10:00:44 -0800 Subject: [PATCH 37/64] feat: add an option specifying when source buffer removals happen (#6242) Increases the default required removal duration from `0.01` => `1.0`. Closes #6240. --- demo/config.js | 2 ++ externs/shaka/player.js | 5 +++++ lib/media/streaming_engine.js | 6 ++++-- lib/util/player_configuration.js | 1 + 4 files changed, 12 insertions(+), 2 deletions(-) diff --git a/demo/config.js b/demo/config.js index ba270d2af2..4762a5bb7f 100644 --- a/demo/config.js +++ b/demo/config.js @@ -420,6 +420,8 @@ shakaDemo.Config = class { /* canBeDecimal= */ true) .addNumberInput_('Buffer Behind', 'streaming.bufferBehind', /* canBeDecimal= */ true) + .addNumberInput_('Eviction Goal', 'streaming.evictionGoal', + /* canBeDecimal= */ true) .addNumberInput_('Safe Seek Offset', 'streaming.safeSeekOffset', /* canBeDecimal= */ true) .addNumberInput_('Stall Threshold', 'streaming.stallThreshold', diff --git a/externs/shaka/player.js b/externs/shaka/player.js index d7799cf266..ce1e764769 100644 --- a/externs/shaka/player.js +++ b/externs/shaka/player.js @@ -1137,6 +1137,7 @@ shaka.extern.ManifestConfiguration; * rebufferingGoal: number, * bufferingGoal: number, * bufferBehind: number, + * evictionGoal: number, * ignoreTextStreamFailures: boolean, * alwaysStreamText: boolean, * startAtSegmentBoundary: boolean, @@ -1198,6 +1199,10 @@ shaka.extern.ManifestConfiguration; * The maximum number of seconds of content that the StreamingEngine will keep * in buffer behind the playhead when it appends a new media segment. * The StreamingEngine will evict content to meet this limit. + * @property {number} evictionGoal + * The minimum duration in seconds of buffer overflow the StreamingEngine + * requires to start removing content from the buffer. + * Values less than 1.0 are not recommended. * @property {boolean} ignoreTextStreamFailures * If true, the player will ignore text stream failures and * continue playing other streams. diff --git a/lib/media/streaming_engine.js b/lib/media/streaming_engine.js index cf5e0293d1..a33eedc4b1 100644 --- a/lib/media/streaming_engine.js +++ b/lib/media/streaming_engine.js @@ -2346,13 +2346,14 @@ shaka.media.StreamingEngine = class { const bufferedBehind = presentationTime - startTime; const overflow = bufferedBehind - bufferBehind; - // See: https://github.com/shaka-project/shaka-player/issues/2982 - if (overflow <= 0.01) { + // See: https://github.com/shaka-project/shaka-player/issues/6240 + if (overflow <= this.config_.evictionGoal) { shaka.log.v2(logPrefix, 'buffer behind okay:', 'presentationTime=' + presentationTime, 'bufferedBehind=' + bufferedBehind, 'bufferBehind=' + bufferBehind, + 'evictionGoal=' + this.config_.evictionGoal, 'underflow=' + Math.abs(overflow)); return; } @@ -2362,6 +2363,7 @@ shaka.media.StreamingEngine = class { 'presentationTime=' + presentationTime, 'bufferedBehind=' + bufferedBehind, 'bufferBehind=' + bufferBehind, + 'evictionGoal=' + this.config_.evictionGoal, 'overflow=' + overflow); await this.playerInterface_.mediaSourceEngine.remove(mediaState.type, diff --git a/lib/util/player_configuration.js b/lib/util/player_configuration.js index f662c66b06..bcb6479448 100644 --- a/lib/util/player_configuration.js +++ b/lib/util/player_configuration.js @@ -191,6 +191,7 @@ shaka.util.PlayerConfiguration = class { rebufferingGoal: 2, bufferingGoal: 10, bufferBehind: 30, + evictionGoal: 1, ignoreTextStreamFailures: false, alwaysStreamText: false, startAtSegmentBoundary: false, From fd57e7f48a01ffbdf296d48b80089078b410eac7 Mon Sep 17 00:00:00 2001 From: theodab Date: Mon, 12 Feb 2024 11:56:09 -0800 Subject: [PATCH 38/64] fix(preload): Fix timing of call to stopQueuingLatePhaseQueuedOperations (#6238) This method should be called after the load is successful, not if the load fails. This also adds a new test that ensures that onKeyStatus_ messages work correctly, as a regression test. This was exposed by the test failures, but was not the cause of them. Issue #6225 --- lib/player.js | 2 +- test/player_unit.js | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/lib/player.js b/lib/player.js index 5ee0e44a8b..4899b81175 100644 --- a/lib/player.js +++ b/lib/player.js @@ -1557,13 +1557,13 @@ shaka.Player = class extends shaka.util.FakeEventTarget { await this.loadInner_( startTimeOfLoad, prefetchedVariant, segmentPrefetchById); }, 'loadInner_'); + preloadManager.stopQueuingLatePhaseQueuedOperations(); } this.dispatchEvent(shaka.Player.makeEvent_( shaka.util.FakeEvent.EventName.Loaded)); } catch (error) { if (error.code != shaka.util.Error.Code.LOAD_INTERRUPTED) { await this.unload(/* initializeMediaSource= */ false); - preloadManager.stopQueuingLatePhaseQueuedOperations(); } throw error; } finally { diff --git a/test/player_unit.js b/test/player_unit.js index d1ee7b1f89..ea4e837762 100644 --- a/test/player_unit.js +++ b/test/player_unit.js @@ -715,6 +715,22 @@ describe('Player', () => { expect(player.getLoadMode()).toBe(shaka.Player.LoadMode.MEDIA_SOURCE); }); }); + + it('fires keystatuschanged events', async () => { + const keyStatusChanged = jasmine.createSpy('keyStatusChanged'); + player.addEventListener( + 'keystatuschanged', Util.spyFunc(keyStatusChanged)); + player.createDrmEngine = (playerInterface) => { + // Call the onKeyStatus on the playerInterface, before load is finished. + playerInterface.onKeyStatus({ + 'aaa': 'usable', + 'bbb': 'output-restricted', + }); + return drmEngine; + }; + await player.load(fakeManifestUri, 0, fakeMimeType); + expect(keyStatusChanged).toHaveBeenCalled(); + }); }); // describe('load/unload') describe('getConfiguration', () => { From 948660b3590bbfacc53bdfb339f36c17dfaf338c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Velad=20Galv=C3=A1n?= Date: Wed, 14 Feb 2024 18:06:57 +0100 Subject: [PATCH 39/64] fix: don't double wrap URIs for HLS key requests (#6246) The `constructSegmentUris` util already returns an array, so the call to `makeRequest` was being made with an array of arrays. This wasn't causing errors for requests that use the `fetch` plugin, since `fetch` will stringify the first argument if it's an array. But the data URI plugin expects to receive a string and calls `.split()` on it, so keys using data URIs throw an error if the URI is wrapped in an array. Thanks to https://github.com/shaka-project/shaka-player/pull/6243 and @andrew0 --- lib/hls/hls_parser.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/hls/hls_parser.js b/lib/hls/hls_parser.js index 21d332d03d..90fac0d304 100644 --- a/lib/hls/hls_parser.js +++ b/lib/hls/hls_parser.js @@ -2845,12 +2845,12 @@ shaka.hls.HlsParser = class { // Don't download the key object until the segment is parsed, to avoid a // startup delay for long manifests with lots of keys. keyInfo.fetchKey = async () => { - const keyUri = shaka.hls.Utils.constructSegmentUris( + const keyUris = shaka.hls.Utils.constructSegmentUris( getUris(), drmTag.getRequiredAttrValue('URI'), variables); const requestType = shaka.net.NetworkingEngine.RequestType.KEY; const request = shaka.net.NetworkingEngine.makeRequest( - [keyUri], this.config_.retryParameters); + keyUris, this.config_.retryParameters); const keyResponse = await this.makeNetworkRequest_(request, requestType); From 5a025fbccd538d3e95a3fe6a878a398c93d4ae9e Mon Sep 17 00:00:00 2001 From: Casey Occhialini <1508707+littlespex@users.noreply.github.com> Date: Thu, 15 Feb 2024 13:54:25 -0800 Subject: [PATCH 40/64] feat: add includeKeys to CMCD config to allow filtering of CMCD data (#6248) This PR adds the ability to filter/limit the amount of data transmitted when CMCD is enabled. It matches the functionality provided in [`dash.js`](https://github.com/Dash-Industry-Forum/dash.js/blob/9e3da3cb35da71d339444158db359bfec63035a0/src/core/Settings.js#L712-L713) and [`hls.js`](https://github.com/video-dev/hls.js/blob/dfb384dc765f400ea3d401b790cfc4d53a44410f/src/config.ts#L70-L75) and addresses concernes raised by video providers: https://github.com/cta-wave/common-media-client-data/issues/122 --- externs/shaka/player.js | 6 +++++- lib/util/cmcd_manager.js | 29 +++++++++++++++++++++++++++-- lib/util/player_configuration.js | 1 + test/util/cmcd_manager_unit.js | 15 +++++++++++++++ 4 files changed, 48 insertions(+), 3 deletions(-) diff --git a/externs/shaka/player.js b/externs/shaka/player.js index ce1e764769..7923862167 100644 --- a/externs/shaka/player.js +++ b/externs/shaka/player.js @@ -1536,7 +1536,8 @@ shaka.extern.AdvancedAbrConfiguration; * useHeaders: boolean, * sessionId: string, * contentId: string, - * rtpSafetyFactor: number + * rtpSafetyFactor: number, + * includeKeys: !Array * }} * * @description @@ -1562,6 +1563,9 @@ shaka.extern.AdvancedAbrConfiguration; * @property {number} rtpSafetyFactor * RTP safety factor. * Defaults to 5. + * @property {!Array} includeKeys + * An array of keys to include in the CMCD data. If not provided, all keys + * will be included. * @exportDoc */ shaka.extern.CmcdConfiguration; diff --git a/lib/util/cmcd_manager.js b/lib/util/cmcd_manager.js index 757d67ff09..ec5619ea1d 100644 --- a/lib/util/cmcd_manager.js +++ b/lib/util/cmcd_manager.js @@ -369,15 +369,17 @@ shaka.util.CmcdManager = class { data.su = this.buffering_; } + const output = this.filterKeys_(data); + if (useHeaders) { - const headers = shaka.util.CmcdManager.toHeaders(data); + const headers = shaka.util.CmcdManager.toHeaders(output); if (!Object.keys(headers).length) { return; } Object.assign(request.headers, headers); } else { - const query = shaka.util.CmcdManager.toQuery(data); + const query = shaka.util.CmcdManager.toQuery(output); if (!query) { return; } @@ -388,6 +390,29 @@ shaka.util.CmcdManager = class { } } + /** + * Filter the CMCD data object to include only the keys specified in the + * configuration. + * + * @param {CmcdData} data + * @return {CmcdData} + * @private + */ + filterKeys_(data) { + const includeKeys = this.config_.includeKeys; + + if (!includeKeys.length) { + return data; + } + + return Object.keys(data).reduce((acc, key) => { + if (includeKeys.includes(key)) { + acc[key] = data[key]; + } + return acc; + }, {}); + } + /** * The CMCD object type. * diff --git a/lib/util/player_configuration.js b/lib/util/player_configuration.js index bcb6479448..ca0ba0389d 100644 --- a/lib/util/player_configuration.js +++ b/lib/util/player_configuration.js @@ -327,6 +327,7 @@ shaka.util.PlayerConfiguration = class { contentId: '', rtpSafetyFactor: 5, useHeaders: false, + includeKeys: [], }; const cmsd = { diff --git a/test/util/cmcd_manager_unit.js b/test/util/cmcd_manager_unit.js index 76168eea3b..c454d44d0a 100644 --- a/test/util/cmcd_manager_unit.js +++ b/test/util/cmcd_manager_unit.js @@ -129,6 +129,7 @@ describe('CmcdManager', () => { contentId: 'testing', rtpSafetyFactor: 5, useHeaders: false, + includeKeys: [], }; /** @type shaka.util.CmcdManager */ @@ -214,11 +215,25 @@ describe('CmcdManager', () => { expect(r.uris[0].includes(sessionId)).toBe(false); expect(sidRegex.test(r.uris[0])).toBe(true); }); + + it('filters keys if includeKeys is provided', () => { + config.sessionId = sid; + config.includeKeys = ['sid', 'cid']; + cmcdManager = new CmcdManager(playerInterface, config); + + const r = ObjectUtils.cloneObject(request); + cmcdManager.applyManifestData(r, manifestInfo); + + const uri = 'https://test.com/test.mpd?CMCD=cid%3D%22testing%22' + + '%2Csid%3D%222ed2d1cd-970b-48f2-bfb3-50a79e87cfa3%22'; + expect(r.uris[0]).toBe(uri); + }); }); describe('query mode', () => { beforeAll(() => { config.sessionId = sid; + config.includeKeys = []; cmcdManager = new CmcdManager(playerInterface, config); }); From bb712c02835f1214be5f23c7f37891eb206ee8e1 Mon Sep 17 00:00:00 2001 From: Justin Swaney Date: Thu, 15 Feb 2024 19:17:07 -0600 Subject: [PATCH 41/64] fix: Fix detection of flac support on Safari (#6250) When constructing the MediaDecodingConfigurations to query media capabilities in `stream_utils.js`, the spelling of "fLaC" should not change to "flac" on Safari. This is because on Safari the query will return `supported: false` for "flac" but `supported: true` for "fLaC". This change allows manifests with "fLaC" codecs to work properly on Safari when using MSE / Managed Media Source. Fixes #6249 --- AUTHORS | 1 + CONTRIBUTORS | 1 + lib/util/stream_utils.js | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/AUTHORS b/AUTHORS index 74bff17d9e..eae29e18a1 100644 --- a/AUTHORS +++ b/AUTHORS @@ -54,6 +54,7 @@ Jonas Birmé Jozef Chúťka Jun Hong Chong Jürgen Kartnaller +Justin Swaney JW Player <*@jwplayer.com> Konstantin Grushetsky Lucas Gabriel Sánchez diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 017b50a658..484a534bec 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -82,6 +82,7 @@ Jozef Chúťka Julian Domingo Jun Hong Chong Jürgen Kartnaller +Justin Swaney Konstantin Grushetsky Leandro Ribeiro Moreira Loïc Raux diff --git a/lib/util/stream_utils.js b/lib/util/stream_utils.js index f274a84875..010e015c69 100644 --- a/lib/util/stream_utils.js +++ b/lib/util/stream_utils.js @@ -915,7 +915,7 @@ shaka.util.StreamUtils = class { // currently don't support 'fLaC', while 'flac' is supported by most // major browsers. // See https://bugs.chromium.org/p/chromium/issues/detail?id=1422728 - if (codecs === 'fLaC') { + if (codecs === 'fLaC' && !shaka.util.Platform.isSafari()) { return 'flac'; } From 03633e47bb3036c2b5fbd60461c7171c1e4ea0ee Mon Sep 17 00:00:00 2001 From: theodab Date: Tue, 20 Feb 2024 00:37:33 -0800 Subject: [PATCH 42/64] feat(text): Add time context to modifyCueCallback (#6252) --- externs/shaka/text.js | 6 ++++-- lib/text/text_engine.js | 2 +- test/text/text_engine_unit.js | 6 ++++-- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/externs/shaka/text.js b/externs/shaka/text.js index 2f34b7cabf..61ec1ee941 100644 --- a/externs/shaka/text.js +++ b/externs/shaka/text.js @@ -87,9 +87,11 @@ shaka.extern.TextParser.TimeContext; /** * A callback used for editing cues before appending. - * Provides the cue, and the URI of the captions file the cue was parsed from. + * Provides the cue, the URI of the captions file the cue was parsed from, and + * the time context that was used when generating that cue. * You can edit the cue object passed in. - * @typedef {function(!shaka.text.Cue, ?string)} + * @typedef {function(!shaka.text.Cue, ?string, + * !shaka.extern.TextParser.TimeContext)} * @exportDoc */ shaka.extern.TextParser.ModifyCueCallback; diff --git a/lib/text/text_engine.js b/lib/text/text_engine.js index 97e85f154b..f6d257306b 100644 --- a/lib/text/text_engine.js +++ b/lib/text/text_engine.js @@ -209,7 +209,7 @@ shaka.text.TextEngine = class { const allCues = this.parser_.parseMedia( shaka.util.BufferUtils.toUint8(buffer), time, uri); for (const cue of allCues) { - this.modifyCueCallback_(cue, uri || null); + this.modifyCueCallback_(cue, uri || null, time); } const cuesToAppend = allCues.filter((cue) => { return cue.startTime >= this.appendWindowStart_ && diff --git a/test/text/text_engine_unit.js b/test/text/text_engine_unit.js index 2231279abd..134519785c 100644 --- a/test/text/text_engine_unit.js +++ b/test/text/text_engine_unit.js @@ -144,8 +144,10 @@ describe('TextEngine', () => { shaka.test.Util.spyFunc(modifyCueCallback)); mockParseMedia.and.returnValue([cue1, cue2]); await textEngine.appendBuffer(dummyData, 0, 3, 'uri'); - expect(modifyCueCallback).toHaveBeenCalledWith(cue1, 'uri'); - expect(modifyCueCallback).toHaveBeenCalledWith(cue2, 'uri'); + expect(modifyCueCallback).toHaveBeenCalledWith( + cue1, 'uri', jasmine.objectContaining({periodStart: 0})); + expect(modifyCueCallback).toHaveBeenCalledWith( + cue2, 'uri', jasmine.objectContaining({periodStart: 0})); }); }); From 58d946e35aa611cc107b4dc77b4729cc34a5caa2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wojciech=20Tyczy=C5=84ski?= Date: Tue, 20 Feb 2024 19:03:10 +0100 Subject: [PATCH 43/64] perf: Optimize init segment reference comparison for common case (#6014) --- lib/media/segment_reference.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/media/segment_reference.js b/lib/media/segment_reference.js index 0274f2dccb..dfe976547c 100644 --- a/lib/media/segment_reference.js +++ b/lib/media/segment_reference.js @@ -129,7 +129,10 @@ shaka.media.InitSegmentReference = class { static equal(reference1, reference2) { const ArrayUtils = shaka.util.ArrayUtils; const BufferUtils = shaka.util.BufferUtils; - if (!reference1 || !reference2) { + + if (reference1 === reference2) { + return true; + } else if (!reference1 || !reference2) { return reference1 == reference2; } else { return reference1.getStartByte() == reference2.getStartByte() && From 0de7af94cd995b29496705523e10cfd004c9e554 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wojciech=20Tyczy=C5=84ski?= Date: Tue, 20 Feb 2024 19:09:31 +0100 Subject: [PATCH 44/64] fix(DASH): Use labels to stitch streams across periods (#6121) If available streams differ only by label, PeriodCombiner does not take it into account when looking for the best candidate. Due to that streams from newly arrived periods will create new audio tracks, as existing streams match always with firstly found stream from new period. Issue has been mitigated by recent PeriodCombiner improvements, as label has been used for hash generation. But if hash don't match i.e. due to bandwidth change, issue would still appear. --- lib/util/periods.js | 24 ++++++++++++++- test/util/periods_unit.js | 64 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 87 insertions(+), 1 deletion(-) diff --git a/lib/util/periods.js b/lib/util/periods.js index b72a59f051..211874acc3 100644 --- a/lib/util/periods.js +++ b/lib/util/periods.js @@ -1234,7 +1234,18 @@ shaka.util.PeriodCombiner = class { return false; } - // If language-based differences haven't decided this, look at roles. If + // If language-based differences haven't decided this, look at labels. + // If available options differ, look does any matches with output stream. + if (best.label !== candidate.label) { + if (outputStream.label === best.label) { + return false; + } + if (outputStream.label === candidate.label) { + return true; + } + } + + // If label-based differences haven't decided this, look at roles. If // the candidate has more roles in common with the output, upgrade to the // candidate. if (outputStream.roles.length) { @@ -1429,6 +1440,17 @@ shaka.util.PeriodCombiner = class { return false; } + // If language-based differences haven't decided this, look at labels. + // If available options differ, look does any matches with output stream. + if (best.label !== candidate.label) { + if (outputStream.label === best.label) { + return false; + } + if (outputStream.label === candidate.label) { + return true; + } + } + // If the candidate has more roles in common with the output, upgrade to the // candidate. if (outputStream.roles.length) { diff --git a/test/util/periods_unit.js b/test/util/periods_unit.js index 8ae68f3168..9f9cc36304 100644 --- a/test/util/periods_unit.js +++ b/test/util/periods_unit.js @@ -1060,6 +1060,70 @@ describe('PeriodCombiner', () => { expect(audio2.originalId).toBe('2,4'); }); + it('Matches streams with labels', async () => { + const stream1 = makeAudioStream('en', /* channels= */ 2); + stream1.originalId = '1'; + stream1.bandwidth = 129597; + stream1.codecs = 'mp4a.40.2'; + + const stream2 = makeAudioStream('en', /* channels= */ 2); + stream2.originalId = '2'; + stream2.bandwidth = 129637; + stream2.codecs = 'mp4a.40.2'; + stream2.label = 'description'; + + const stream3 = makeAudioStream('en', /* channels= */ 2); + stream3.originalId = '3'; + stream3.bandwidth = 131037; + stream3.codecs = 'mp4a.40.2'; + + const stream4 = makeAudioStream('en', /* channels= */ 2); + stream4.originalId = '4'; + stream4.bandwidth = 131034; + stream4.codecs = 'mp4a.40.2'; + stream4.label = 'description'; + + /** @type {!Array.} */ + const periods = [ + { + id: '0', + videoStreams: [ + makeVideoStream(1080), + ], + audioStreams: [ + stream1, + stream2, + ], + textStreams: [], + imageStreams: [], + }, + { + id: '1', + videoStreams: [ + makeVideoStream(1080), + ], + audioStreams: [ + stream3, + stream4, + ], + textStreams: [], + imageStreams: [], + }, + ]; + + await combiner.combinePeriods(periods, /* isDynamic= */ true); + const variants = combiner.getVariants(); + expect(variants.length).toBe(2); + // We can use the originalId field to see what each track is composed of. + const audio1 = variants[0].audio; + expect(audio1.label).toBe(null); + expect(audio1.originalId).toBe('1,3'); + + const audio2 = variants[1].audio; + expect(audio2.label).toBe('description'); + expect(audio2.originalId).toBe('2,4'); + }); + it('Matches streams with related codecs', async () => { const stream1 = makeVideoStream(1080); stream1.originalId = '1'; From 4a0d1ca06fe54975a344c9bb745d908b2588f566 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wojciech=20Tyczy=C5=84ski?= Date: Tue, 20 Feb 2024 19:23:06 +0100 Subject: [PATCH 45/64] fix(DASH): Fix precision issue on some platforms (#6258) When recalculations of period end are made, it is possible that we will not be able to find last segment from period on low precision platforms. To mitigate it, try to use cached value of `periodEnd_` whenever possible. Issue observed on Xbox One & Xbox Series. --- lib/dash/segment_template.js | 31 +++++++++++-------- .../dash/dash_parser_segment_template_unit.js | 2 +- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/lib/dash/segment_template.js b/lib/dash/segment_template.js index fb66516cde..57fc09b0d2 100644 --- a/lib/dash/segment_template.js +++ b/lib/dash/segment_template.js @@ -755,16 +755,10 @@ shaka.dash.TimelineSegmentIndex = class extends shaka.media.SegmentIndex { this.evict(this.periodStart_); - if (timeline.length === 0) { - return; - } - - if (this.periodEnd_ !== Infinity) { - // Adjust the last timeline entry to match the period end - const lastTimePeriod = timeline[timeline.length - 1]; - // NOTE: end should be relative to period start - lastTimePeriod.end = this.periodEnd_ - this.periodStart_; - } + // Do NOT adjust last range to match period end! With high precision + // timestamps several recalculations may give wrong results on less precise + // platforms. To mitigate that, we're using cached |periodEnd_| value in + // find/get() methods whenever possible. } /** @@ -784,7 +778,7 @@ shaka.dash.TimelineSegmentIndex = class extends shaka.media.SegmentIndex { const timeline = this.templateInfo_.timeline; // Early exit if the time isn't within this period - if (time < this.periodStart_ || time > this.periodEnd_) { + if (time < this.periodStart_ || time >= this.periodEnd_) { return null; } @@ -797,10 +791,14 @@ shaka.dash.TimelineSegmentIndex = class extends shaka.media.SegmentIndex { // the references by a fraction of a second. To account for this, we use // the start of the next segment as /end/, unless this is the last // reference, in which case we use the period end as the /end/ - let end = range.end + this.periodStart_; + let end; if (i < lastIndex) { end = timeline[i + 1].start + this.periodStart_; + } else if (this.periodEnd_ === Infinity) { + end = range.end + this.periodStart_; + } else { + end = this.periodEnd_; } if ((time >= start) && (time < end)) { @@ -831,6 +829,12 @@ shaka.dash.TimelineSegmentIndex = class extends shaka.media.SegmentIndex { .unscaledPresentationTimeOffset + range.unscaledStart; const timestampOffset = this.periodStart_ - this.templateInfo_.scaledPresentationTimeOffset; + const trueSegmentEnd = this.periodStart_ + range.end; + let segmentEnd = trueSegmentEnd; + if (correctedPosition === this.getNumReferences() - 1 && + this.periodEnd_ !== Infinity) { + segmentEnd = this.periodEnd_; + } const partialSegmentRefs = []; @@ -901,7 +905,7 @@ shaka.dash.TimelineSegmentIndex = class extends shaka.media.SegmentIndex { ref = new shaka.media.SegmentReference( this.periodStart_ + range.start, - this.periodStart_ + range.end, + segmentEnd, createUrisCb, /* startByte= */ 0, /* endByte= */ null, @@ -916,6 +920,7 @@ shaka.dash.TimelineSegmentIndex = class extends shaka.media.SegmentIndex { shaka.media.SegmentReference.Status.AVAILABLE, this.aesKey_, /* allPartialSegments= */ range.partialSegments > 0); + ref.trueEndTime = trueSegmentEnd; this.references[correctedPosition] = ref; } diff --git a/test/dash/dash_parser_segment_template_unit.js b/test/dash/dash_parser_segment_template_unit.js index 6906ab5296..032ee8a59d 100644 --- a/test/dash/dash_parser_segment_template_unit.js +++ b/test/dash/dash_parser_segment_template_unit.js @@ -786,7 +786,7 @@ describe('DashParser SegmentTemplate', () => { const newTemplateInfo = makeTemplateInfo(newRanges); const newEnd = newRanges[newRanges.length - 1].end; - index.appendTemplateInfo(newTemplateInfo, newEnd); + index.appendTemplateInfo(newTemplateInfo, /* periodStart= */ 0, newEnd); expect(index.find(newStart)).toBe(10); expect(index.find(newEnd - 1.0)).toBe(19); }); From de2957e8fa417f1bf741b2cb4da5f68adf3cc221 Mon Sep 17 00:00:00 2001 From: Vasanthavanan Devarajan Date: Wed, 21 Feb 2024 00:12:20 +0530 Subject: [PATCH 46/64] feat: Add config to set live stream duration to Infinity (#6207) Fixes: https://github.com/shaka-project/shaka-player/issues/6205 --- demo/config.js | 6 +++--- externs/shaka/player.js | 7 ++++++- lib/media/streaming_engine.js | 6 +++++- lib/util/player_configuration.js | 1 + 4 files changed, 15 insertions(+), 5 deletions(-) diff --git a/demo/config.js b/demo/config.js index 4762a5bb7f..bf6de21cc1 100644 --- a/demo/config.js +++ b/demo/config.js @@ -493,9 +493,9 @@ shakaDemo.Config = class { /* canBeDecimal= */ true) .addNumberInput_('VOD Dynamic Playback Rate Buffer Ratio', 'streaming.vodDynamicPlaybackRateBufferRatio', - /* canBeDecimal= */ true); - - + /* canBeDecimal= */ true) + .addBoolInput_('Infinite Live Stream Duration', + 'streaming.infiniteLiveStreamDuration'); if (!shakaDemoMain.getNativeControlsEnabled()) { this.addBoolInput_('Always Stream Text', 'streaming.alwaysStreamText'); } else { diff --git a/externs/shaka/player.js b/externs/shaka/player.js index 7923862167..3de7efa3d1 100644 --- a/externs/shaka/player.js +++ b/externs/shaka/player.js @@ -1175,7 +1175,8 @@ shaka.extern.ManifestConfiguration; * minTimeBetweenRecoveries: number, * vodDynamicPlaybackRate: boolean, * vodDynamicPlaybackRateLowBufferRate: number, - * vodDynamicPlaybackRateBufferRatio: number + * vodDynamicPlaybackRateBufferRatio: number, + * infiniteLiveStreamDuration: boolean * }} * * @description @@ -1357,6 +1358,10 @@ shaka.extern.ManifestConfiguration; * setting the playback rate to * vodDynamicPlaybackRateLowBufferRate. * Defaults to 0.5. + * @property {boolean} infiniteLiveStreamDuration + * If true, the media source live duration + * set as aInfinity + * Defaults to false . * @exportDoc */ shaka.extern.StreamingConfiguration; diff --git a/lib/media/streaming_engine.js b/lib/media/streaming_engine.js index a33eedc4b1..a7da731857 100644 --- a/lib/media/streaming_engine.js +++ b/lib/media/streaming_engine.js @@ -1087,9 +1087,13 @@ shaka.media.StreamingEngine = class { if (duration < Infinity) { this.playerInterface_.mediaSourceEngine.setDuration(duration); } else { + // To set the media source live duration as Infinity + // If infiniteLiveStreamDuration as true + const duration = + this.config_.infiniteLiveStreamDuration ? Infinity : Math.pow(2, 32); // Not all platforms support infinite durations, so set a finite duration // so we can append segments and so the user agent can seek. - this.playerInterface_.mediaSourceEngine.setDuration(Math.pow(2, 32)); + this.playerInterface_.mediaSourceEngine.setDuration(duration); } } diff --git a/lib/util/player_configuration.js b/lib/util/player_configuration.js index ca0ba0389d..4af68deeea 100644 --- a/lib/util/player_configuration.js +++ b/lib/util/player_configuration.js @@ -239,6 +239,7 @@ shaka.util.PlayerConfiguration = class { vodDynamicPlaybackRate: false, vodDynamicPlaybackRateLowBufferRate: 0.95, vodDynamicPlaybackRateBufferRatio: 0.5, + infiniteLiveStreamDuration: false, }; // WebOS, Tizen, Chromecast and Hisense have long hardware pipelines From d228ca4fd92cf185bbf266967f30be873be882b5 Mon Sep 17 00:00:00 2001 From: Joey Parrish Date: Tue, 20 Feb 2024 16:59:40 -0800 Subject: [PATCH 47/64] test: Skip H265 Transmuxer tests in Chrome on Windows (#6261) --- test/transmuxer/transmuxer_integration.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/transmuxer/transmuxer_integration.js b/test/transmuxer/transmuxer_integration.js index 8a6a3d3f3f..69962d5a0c 100644 --- a/test/transmuxer/transmuxer_integration.js +++ b/test/transmuxer/transmuxer_integration.js @@ -305,10 +305,10 @@ filterDescribe('Transmuxer Player', checkNoBrokenEdge, () => { it('H.265 in TS', async () => { const chromeVersion = shaka.util.Platform.chromeVersion(); - if (shaka.util.Platform.isWindows() && - chromeVersion && chromeVersion === 117) { - // It appears that Chrome 117 beta in Windows is incorrectly reporting - // H.265 in MediaCapabilities + if (shaka.util.Platform.isWindows() && chromeVersion) { + // It appears that Chrome 122 in Windows is still incorrectly reporting + // H.265 in MediaSource. Revisit this with a maximum chromeVersion if + // Chrome ever fixes it. pending('Codec H.265 is not supported by the platform.'); } const mimeType = 'video/mp4; codecs="hvc1.2.4.L123.B0"'; From b8905bd8d44217b80dee8bb93ad306f55c145764 Mon Sep 17 00:00:00 2001 From: Joey Parrish Date: Wed, 21 Feb 2024 09:43:40 -0800 Subject: [PATCH 48/64] fix(Cast): Force TS content to be transmuxed on Chromecast (#6262) Although Chromecast natively supports TS content, it does not work in all cases. In particular, we have some sample live streams where some TS segments can be parsed by external tools as valid TS, but cause the Chromecast to throw a parsing error. We should reject TS content on Chromecast, and allow the builtin transmuxer to take over parsing. This also removes the use of `cast.__platform__.canDisplayType` to patch MediaSource.isTypeSupported on Chromecast. Current versions of Shaka Player are doing very rough filtering with isTypeSupported before calling MediaCapabilities.decodingInfo. And our MediaCapabilities polyfill calls `cast.__platform__.canDisplayType` directly, bypassing any polyfill we might install on isTypeSupported. So there is no longer any purpose to canDisplayType in isTypeSupported. Closes #5278 --- lib/polyfill/mediasource.js | 41 +++++-------------------------------- 1 file changed, 5 insertions(+), 36 deletions(-) diff --git a/lib/polyfill/mediasource.js b/lib/polyfill/mediasource.js index 60dad0304f..eab2978814 100644 --- a/lib/polyfill/mediasource.js +++ b/lib/polyfill/mediasource.js @@ -32,11 +32,12 @@ shaka.polyfill.MediaSource = class { if (!window.MediaSource) { shaka.log.info('No MSE implementation available.'); - } else if (window.cast && cast.__platform__ && - cast.__platform__.canDisplayType) { + } else if (shaka.util.Platform.isChromecast()) { shaka.log.info('Patching Chromecast MSE bugs.'); - // Chromecast cannot make accurate determinations via isTypeSupported. - shaka.polyfill.MediaSource.patchCastIsTypeSupported_(); + // Chromecast fails on some TS content, even though it is supposed to + // support it. Better to transmux. + // See https://github.com/shaka-project/shaka-player/issues/5278 + shaka.polyfill.MediaSource.rejectContainer_('mp2t'); } else if (safariVersion) { // NOTE: shaka.Player.isBrowserSupported() has its own restrictions on // Safari version. @@ -182,38 +183,6 @@ shaka.polyfill.MediaSource = class { }; } - /** - * Patch isTypeSupported() to chain to a private API on the Chromecast which - * can query for support of detailed content parameters. - * - * @private - */ - static patchCastIsTypeSupported_() { - const originalIsTypeSupported = MediaSource.isTypeSupported; - - MediaSource.isTypeSupported = (mimeType) => { - // Parse the basic MIME type from its parameters. - const pieces = mimeType.split(/ *; */); - pieces.shift(); // Remove basic MIME type from pieces. - - const hasCodecs = pieces.some((piece) => piece.startsWith('codecs=')); - if (!hasCodecs) { - // Though the original reason for this special case was not documented, - // it is presumed to be because the platform won't accept a MIME type - // without codecs in canDisplayType. It is valid, however, in - // isTypeSupported. - return originalIsTypeSupported(mimeType); - } - - // Only canDisplayType can check extended MIME type parameters on this - // platform (such as frame rate, resolution, etc). - // In previous versions of this polyfill, the MIME type parameters were - // manipulated, filtered, or extended. This is no longer true, so we pass - // the full MIME type to the platform as we received it. - return cast.__platform__.canDisplayType(mimeType); - }; - } - /** * Patch isTypeSupported() to translate vp09 codec strings into vp9, to allow * such content to play on older smart TVs. From ddc24998ab403db4b359c9dad24b1dac2437e303 Mon Sep 17 00:00:00 2001 From: Joey Parrish Date: Wed, 21 Feb 2024 13:25:22 -0800 Subject: [PATCH 49/64] ci: Unfork less.js (#6268) The issue we had in less.js v4 has since been resolved. This updates to less.js v4.2.0, which includes the underlying fix from its dependency, needle v3.1.0. Unforking also resolves CI issues where gitpkg.now.sh temporarily fails to load, causing the whole test run to fail before it can start. --- package-lock.json | 51 ++++++++++++++--------------------------------- package.json | 2 +- 2 files changed, 16 insertions(+), 37 deletions(-) diff --git a/package-lock.json b/package-lock.json index 909e105a39..73a73a3404 100644 --- a/package-lock.json +++ b/package-lock.json @@ -50,7 +50,7 @@ "karma-spec-reporter": "^0.0.34", "karma-webdriver-launcher": "^1.0.8", "lcevc_dec.js": "^1.0.1", - "less": "https://gitpkg.now.sh/joeyparrish/less.js/packages/less?28c63a43", + "less": "^4.2.0", "less-plugin-clean-css": "github:austingardner/less-plugin-clean-css#4e9e77bf", "material-design-lite": "^1.3.0", "open-sans-fonts": "^1.6.2", @@ -5795,11 +5795,10 @@ } }, "node_modules/less": { - "version": "4.1.2", - "resolved": "https://gitpkg.now.sh/joeyparrish/less.js/packages/less?28c63a43", - "integrity": "sha512-AxZPQSmyVgtkNwrSXux9yYU0Kskcvj6AcAjWRmvyLAIkLaXRDN660R2XcsRNavXOr6tCQknVw5TvRtvCPiOW0Q==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/less/-/less-4.2.0.tgz", + "integrity": "sha512-P3b3HJDBtSzsXUl0im2L7gTO5Ubg8mEN6G8qoTS77iXxXX4Hvu4Qj540PZDvQ8V6DmX6iXo98k7Md0Cm1PrLaA==", "dev": true, - "license": "Apache-2.0", "dependencies": { "copy-anything": "^2.0.1", "parse-node-version": "^1.0.1", @@ -5817,7 +5816,7 @@ "image-size": "~0.5.0", "make-dir": "^2.1.0", "mime": "^1.4.1", - "needle": "github:joeyparrish/needle#86b2c2ff", + "needle": "^3.1.0", "source-map": "~0.6.0" } }, @@ -6324,13 +6323,12 @@ "dev": true }, "node_modules/needle": { - "version": "3.0.1", - "resolved": "git+ssh://git@github.com/joeyparrish/needle.git#86b2c2fffc35b4a6433482ea5ebcc1837702d26f", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/needle/-/needle-3.3.1.tgz", + "integrity": "sha512-6k0YULvhpw+RoLNiQCRKOl09Rv1dPLr8hHnVjHqdolKwDrdNyk+Hmrthi4lIGPPz3r39dLx0hsF5s40sZ3Us4Q==", "dev": true, - "license": "MIT", "optional": true, "dependencies": { - "debug": "^3.2.6", "iconv-lite": "^0.6.3", "sax": "^1.2.4" }, @@ -6341,16 +6339,6 @@ "node": ">= 4.4.x" } }, - "node_modules/needle/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "optional": true, - "dependencies": { - "ms": "^2.1.1" - } - }, "node_modules/needle/node_modules/iconv-lite": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", @@ -13165,8 +13153,9 @@ } }, "less": { - "version": "https://gitpkg.now.sh/joeyparrish/less.js/packages/less?28c63a43", - "integrity": "sha512-AxZPQSmyVgtkNwrSXux9yYU0Kskcvj6AcAjWRmvyLAIkLaXRDN660R2XcsRNavXOr6tCQknVw5TvRtvCPiOW0Q==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/less/-/less-4.2.0.tgz", + "integrity": "sha512-P3b3HJDBtSzsXUl0im2L7gTO5Ubg8mEN6G8qoTS77iXxXX4Hvu4Qj540PZDvQ8V6DmX6iXo98k7Md0Cm1PrLaA==", "dev": true, "requires": { "copy-anything": "^2.0.1", @@ -13175,7 +13164,7 @@ "image-size": "~0.5.0", "make-dir": "^2.1.0", "mime": "^1.4.1", - "needle": "github:joeyparrish/needle#86b2c2ff", + "needle": "^3.1.0", "parse-node-version": "^1.0.1", "source-map": "~0.6.0", "tslib": "^2.3.0" @@ -13563,26 +13552,16 @@ "dev": true }, "needle": { - "version": "git+ssh://git@github.com/joeyparrish/needle.git#86b2c2fffc35b4a6433482ea5ebcc1837702d26f", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/needle/-/needle-3.3.1.tgz", + "integrity": "sha512-6k0YULvhpw+RoLNiQCRKOl09Rv1dPLr8hHnVjHqdolKwDrdNyk+Hmrthi4lIGPPz3r39dLx0hsF5s40sZ3Us4Q==", "dev": true, - "from": "needle@github:joeyparrish/needle#86b2c2ff", "optional": true, "requires": { - "debug": "^3.2.6", "iconv-lite": "^0.6.3", "sax": "^1.2.4" }, "dependencies": { - "debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "optional": true, - "requires": { - "ms": "^2.1.1" - } - }, "iconv-lite": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", diff --git a/package.json b/package.json index bcd0ee2e7c..f6168b1049 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,7 @@ "karma-spec-reporter": "^0.0.34", "karma-webdriver-launcher": "^1.0.8", "lcevc_dec.js": "^1.0.1", - "less": "https://gitpkg.now.sh/joeyparrish/less.js/packages/less?28c63a43", + "less": "^4.2.0", "less-plugin-clean-css": "github:austingardner/less-plugin-clean-css#4e9e77bf", "material-design-lite": "^1.3.0", "open-sans-fonts": "^1.6.2", From d795a00d6caf133020b8a0a35fac6d5daa65c733 Mon Sep 17 00:00:00 2001 From: Joey Parrish Date: Wed, 21 Feb 2024 15:28:57 -0800 Subject: [PATCH 50/64] fix(preload): Fix load interruption (#6271) Interrupting load() was causing two concurrent sets of load() operations to happen at once, which led the asset URI for the second operation to be overwritten by the first. This was exposed by a test failure on Safari. There is nothing special about Safari, but the timing happened to work out such that the concurrent load() calls would intefere with each other. This fixes the issue by acquiring the mutex in load() for the preloadManager.start() operation. This issue did not affect any releases. Closes #6225 --- lib/player.js | 4 +++- test/player_load_graph_integration.js | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/player.js b/lib/player.js index 4899b81175..8be4517d09 100644 --- a/lib/player.js +++ b/lib/player.js @@ -1440,11 +1440,13 @@ shaka.Player = class extends shaka.util.FakeEventTarget { // "preload" here without prefetch. // That way, both a preload and normal load can follow the same code // paths. + // NOTE: await preloadInner_ can be outside the mutex because it should + // not mutate "this". preloadManager = await this.preloadInner_( assetUri, startTime, mimeType, /* standardLoad= */ true); if (preloadManager) { preloadManager.setEventHandoffTarget(this); - await preloadManager.start(); + await mutexWrapOperation(() => preloadManager.start(), 'preload'); } } else { // Hook up events, so any events emitted by the preloadManager will diff --git a/test/player_load_graph_integration.js b/test/player_load_graph_integration.js index 27be9657dc..b8c18208d4 100644 --- a/test/player_load_graph_integration.js +++ b/test/player_load_graph_integration.js @@ -756,6 +756,7 @@ describe('Player Load Graph', () => { 'manifest-parser', 'manifest', 'drm-engine', + // Excludes 'unload'. ]); /** @type {!Set.} */ @@ -774,6 +775,7 @@ describe('Player Load Graph', () => { await player.attach(video); player.load('test:sintel').catch(() => {}); } else { + goog.asserts.assert(state == 'unload', 'Unrecognized testing state!'); await player.attach(video); await player.load('test:sintel'); player.unload().catch(() => {}); From 0692e234d1d19926a2e0cf3f8c7c47b12c2737cd Mon Sep 17 00:00:00 2001 From: Joey Parrish Date: Wed, 21 Feb 2024 15:29:54 -0800 Subject: [PATCH 51/64] ci: Tweak command parsing (#6269) - Fix wrong index variable in loop ("i" vs "INDEX") that prevented detection of commands at arbitrary places in a comment. - Fix parsing of comments with newlines. - Normalize commands to lowercase before checking them. - Enhance debugging of command parsing. - Allow the user to say "please" because it just feels nicer to me, even when I'm talking to a robot. --- .github/workflows/shaka-bot-commands/lib.sh | 49 +++++++++++++++----- .github/workflows/shaka-bot-commands/main.sh | 6 ++- .github/workflows/talk-to-shaka-bot.yaml | 1 + 3 files changed, 42 insertions(+), 14 deletions(-) diff --git a/.github/workflows/shaka-bot-commands/lib.sh b/.github/workflows/shaka-bot-commands/lib.sh index e8f018300e..7fb1cb84ff 100644 --- a/.github/workflows/shaka-bot-commands/lib.sh +++ b/.github/workflows/shaka-bot-commands/lib.sh @@ -64,20 +64,45 @@ function start_workflow() { gh workflow run "$WORKFLOW" -R "$THIS_REPO" "${GH_ARGS[@]}" } +# Simple alias for converting a stream of text to lowercase. +function tolower() { + tr '[:upper:]' '[:lower:]' +} + # Outputs to global variables SHAKA_BOT_COMMAND and SHAKA_BOT_ARGUMENTS (array). function parse_command() { - # Tokenize the comment by whitespace. - local TOKENS=( $COMMENT_BODY ) - - local INDEX - for (( INDEX=0; INDEX < ${#TOKENS[@]}; INDEX++ )); do - if [[ "${TOKENS[i]}" == "@shaka-bot" ]]; then - SHAKA_BOT_COMMAND="${TOKENS[i+1]}" - # A slice of all tokens starting with index i+2. - SHAKA_BOT_ARGUMENTS=( "${TOKENS[@]:i+2}" ) - return 0 - fi - done + echo "Parsing comment. Body: \"$COMMENT_BODY\"" + + # Read each line one at a time. Tokens from one line won't affect another. + local COMMENT_LINE + while read COMMENT_LINE; do + echo "Parsing comment. Line: \"$COMMENT_LINE\"" + + # Tokenize the line by whitespace. + local TOKENS=( $COMMENT_LINE ) + + local INDEX + for (( INDEX=0; INDEX < ${#TOKENS[@]}; INDEX++ )); do + if [[ "${TOKENS[INDEX]}" == "@shaka-bot" ]]; then + # The next word is the command. + SHAKA_BOT_COMMAND=$(echo "${TOKENS[INDEX+1]}" | tolower) + + # Unless it's please, then it's the word after that. + if [[ "$SHAKA_BOT_COMMAND" == "please" ]]; then + INDEX=$((INDEX + 1)) + SHAKA_BOT_COMMAND=$(echo "${TOKENS[INDEX+1]}" | tolower) + fi + + # A slice of all tokens starting with index INDEX+2. + SHAKA_BOT_ARGUMENTS=( "${TOKENS[@]:INDEX+2}" ) + return 0 + fi + done + done < <(echo "$COMMENT_BODY" | tr -d '\r') + # The line above pipes COMMENT_BODY, without \r characters, into the loop. + # It is important to maintain the loop in the main shell, not a subshell, so + # that variables it writes to (SHAKA_BOT_COMMAND and SHAKA_BOT_ARGUMENTS) + # affect the caller. return 1 } diff --git a/.github/workflows/shaka-bot-commands/main.sh b/.github/workflows/shaka-bot-commands/main.sh index 52a1e19568..c9339a8c1b 100755 --- a/.github/workflows/shaka-bot-commands/main.sh +++ b/.github/workflows/shaka-bot-commands/main.sh @@ -42,10 +42,12 @@ if [[ "$SHAKA_BOT_COMMAND" == "" ]]; then exit 0 fi -echo "PR $PR_NUMBER, detected command $SHAKA_BOT_COMMAND" +echo "PR $PR_NUMBER" +echo "Detected command \"$SHAKA_BOT_COMMAND\"" +echo "Detected arguments \"$SHAKA_BOT_ARGUMENTS\"" case "$SHAKA_BOT_COMMAND" in help) . command-help.sh ;; test) . command-test.sh ;; - *) echo "Unknown command!" ;; + *) echo "Unknown command" ;; esac diff --git a/.github/workflows/talk-to-shaka-bot.yaml b/.github/workflows/talk-to-shaka-bot.yaml index b0f1f5da1f..f13fd99941 100644 --- a/.github/workflows/talk-to-shaka-bot.yaml +++ b/.github/workflows/talk-to-shaka-bot.yaml @@ -8,6 +8,7 @@ on: jobs: handle_command: + name: Handle Command # Only runs on PRs that contain '@shaka-bot' comments, but not comments # made by shaka-bot itself, who will sometimes use its own name. # Note that contains() is not case sensitive. From d197eb3efce2a015a7f43efe30a0d40bc054b419 Mon Sep 17 00:00:00 2001 From: Joey Parrish Date: Wed, 21 Feb 2024 15:30:20 -0800 Subject: [PATCH 52/64] test: Exclude all H265 tests for Chrome+Windows (#6266) My previous fix only affected one H265 test, not both. I also found some maximum versions in exclusions around AC3/EC3, and removed those, as the issue is still not fixed in Chrome and there is no way to predict when it will get fixed. I would rather not increment that number after every new Chrome release. --- test/transmuxer/transmuxer_integration.js | 44 +++++++++++------------ 1 file changed, 21 insertions(+), 23 deletions(-) diff --git a/test/transmuxer/transmuxer_integration.js b/test/transmuxer/transmuxer_integration.js index 69962d5a0c..d203dcdc8f 100644 --- a/test/transmuxer/transmuxer_integration.js +++ b/test/transmuxer/transmuxer_integration.js @@ -51,6 +51,23 @@ filterDescribe('Transmuxer Player', checkNoBrokenEdge, () => { /** @type {!shaka.test.Waiter} */ let waiter; + function isH265Supported() { + if (!MediaSource.isTypeSupported('video/mp4; codecs="hvc1.2.4.L123.B0"')) { + return false; + } + // As of Chrome 122, Chrome on Windows is still incorrectly reporting H.265 + // support. Revisit this exclusion with a maximum chromeVersion if Chrome + // ever fixes it. + // We don't have a solid bug link for this issue. It's unclear if this is + // specific to GitHub CI systems, which may be missing some codecs. + const chromeVersion = shaka.util.Platform.chromeVersion(); + if (shaka.util.Platform.isWindows() && chromeVersion) { + return false; + } + // https://bugs.chromium.org/p/chromium/issues/detail?id=1450313 + return true; + } + function isAc3Supported() { if (!MediaSource.isTypeSupported('audio/mp4; codecs="ac-3"')) { return false; @@ -64,9 +81,7 @@ filterDescribe('Transmuxer Player', checkNoBrokenEdge, () => { // to true, which leads to a failure in GitHub's environment. // We must enable this, once it is resolved: // https://bugs.chromium.org/p/chromium/issues/detail?id=1450313 - const chromeVersion = shaka.util.Platform.chromeVersion(); - if (shaka.util.Platform.isWindows() && shaka.util.Platform.isEdge() && - chromeVersion && chromeVersion <= 122) { + if (shaka.util.Platform.isWindows() && shaka.util.Platform.isEdge()) { return false; } return true; @@ -85,9 +100,7 @@ filterDescribe('Transmuxer Player', checkNoBrokenEdge, () => { // to true, which leads to a failure in GitHub's environment. // We must enable this, once it is resolved: // https://bugs.chromium.org/p/chromium/issues/detail?id=1450313 - const chromeVersion = shaka.util.Platform.chromeVersion(); - if (shaka.util.Platform.isWindows() && shaka.util.Platform.isEdge() && - chromeVersion && chromeVersion <= 122) { + if (shaka.util.Platform.isWindows() && shaka.util.Platform.isEdge()) { return false; } return true; @@ -304,15 +317,7 @@ filterDescribe('Transmuxer Player', checkNoBrokenEdge, () => { }); it('H.265 in TS', async () => { - const chromeVersion = shaka.util.Platform.chromeVersion(); - if (shaka.util.Platform.isWindows() && chromeVersion) { - // It appears that Chrome 122 in Windows is still incorrectly reporting - // H.265 in MediaSource. Revisit this with a maximum chromeVersion if - // Chrome ever fixes it. - pending('Codec H.265 is not supported by the platform.'); - } - const mimeType = 'video/mp4; codecs="hvc1.2.4.L123.B0"'; - if (!MediaSource.isTypeSupported(mimeType)) { + if (!isH265Supported()) { pending('Codec H.265 is not supported by the platform.'); } await player.load('/base/test/test/assets/hls-ts-h265/hevc.m3u8'); @@ -350,14 +355,7 @@ filterDescribe('Transmuxer Player', checkNoBrokenEdge, () => { }); it('H.265+AAC in TS', async () => { - const chromeVersion = shaka.util.Platform.chromeVersion(); - if (shaka.util.Platform.isWindows() && - chromeVersion && chromeVersion === 117) { - // It appears that Chrome 117 beta in Windows is incorrectly reporting - // H.265 in MediaCapabilities - pending('Codec H.265 is not supported by the platform.'); - } - if (!MediaSource.isTypeSupported('video/mp4; codecs="hvc1.1.6.L93.90"')) { + if (!isH265Supported()) { pending('Codec H.265 is not supported by the platform.'); } // eslint-disable-next-line max-len From 66cb7df6c4e77408e9d0efa098de9f9306cb05a6 Mon Sep 17 00:00:00 2001 From: Joey Parrish Date: Wed, 21 Feb 2024 15:30:30 -0800 Subject: [PATCH 53/64] test: Add missing method in fake SegmentPrefetch (#6265) Closes #6224 --- test/test/util/fake_segment_prefetch.js | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/test/test/util/fake_segment_prefetch.js b/test/test/util/fake_segment_prefetch.js index 10788c9013..71d5b63736 100644 --- a/test/test/util/fake_segment_prefetch.js +++ b/test/test/util/fake_segment_prefetch.js @@ -46,6 +46,11 @@ shaka.test.FakeSegmentPrefetch = class { this.segmentNum_ = 0; } + /** @override */ + replaceFetchDispatcher(fetchDispatcher) { + // empty fake for now + } + /** @override */ getLastKnownPosition() { return this.prefetchPosTime_; @@ -98,10 +103,10 @@ shaka.test.FakeSegmentPrefetch = class { } /** - * @override - * @param {shaka.media.InitSegmentReference| - * shaka.media.SegmentReference} reference - * */ + * @override + * @param {shaka.media.InitSegmentReference| + * shaka.media.SegmentReference} reference + */ getPrefetchedSegment(reference) { if (!(reference instanceof shaka.media.SegmentReference)) { return null; From 4695ac89b564624727e0b4f225eb183bcf1e6435 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 21 Feb 2024 16:36:33 -0800 Subject: [PATCH 54/64] chore(deps): bump xml2js and parse-bmfont-xml (#6270) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/package-lock.json b/package-lock.json index 73a73a3404..765ece60d0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6694,13 +6694,13 @@ "dev": true }, "node_modules/parse-bmfont-xml": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/parse-bmfont-xml/-/parse-bmfont-xml-1.1.4.tgz", - "integrity": "sha512-bjnliEOmGv3y1aMEfREMBJ9tfL3WR0i0CKPj61DnSLaoxWR3nLrsQrEbCId/8rF4NyRF0cCqisSVXyQYWM+mCQ==", + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/parse-bmfont-xml/-/parse-bmfont-xml-1.1.6.tgz", + "integrity": "sha512-0cEliVMZEhrFDwMh4SxIyVJpqYoOWDJ9P895tFuS+XuNzI5UBmBk5U5O4KuJdTnZpSBI4LFA2+ZiJaiwfSwlMA==", "dev": true, "dependencies": { "xml-parse-from-string": "^1.0.0", - "xml2js": "^0.4.5" + "xml2js": "^0.5.0" } }, "node_modules/parse-headers": { @@ -8691,9 +8691,9 @@ "dev": true }, "node_modules/xml2js": { - "version": "0.4.23", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", - "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz", + "integrity": "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==", "dev": true, "dependencies": { "sax": ">=0.6.0", @@ -13833,13 +13833,13 @@ "dev": true }, "parse-bmfont-xml": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/parse-bmfont-xml/-/parse-bmfont-xml-1.1.4.tgz", - "integrity": "sha512-bjnliEOmGv3y1aMEfREMBJ9tfL3WR0i0CKPj61DnSLaoxWR3nLrsQrEbCId/8rF4NyRF0cCqisSVXyQYWM+mCQ==", + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/parse-bmfont-xml/-/parse-bmfont-xml-1.1.6.tgz", + "integrity": "sha512-0cEliVMZEhrFDwMh4SxIyVJpqYoOWDJ9P895tFuS+XuNzI5UBmBk5U5O4KuJdTnZpSBI4LFA2+ZiJaiwfSwlMA==", "dev": true, "requires": { "xml-parse-from-string": "^1.0.0", - "xml2js": "^0.4.5" + "xml2js": "^0.5.0" } }, "parse-headers": { @@ -15362,9 +15362,9 @@ "dev": true }, "xml2js": { - "version": "0.4.23", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", - "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz", + "integrity": "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==", "dev": true, "requires": { "sax": ">=0.6.0", From 6be778f09ad9a4aa6dcf3230fb51739328ad99a5 Mon Sep 17 00:00:00 2001 From: Joey Parrish Date: Thu, 22 Feb 2024 10:10:44 -0800 Subject: [PATCH 55/64] test: Update screenshots and disable GPU to increase screenshot stability (#6264) Some screenshots got out of date while some of our infrastructure was failing in the lab. Some screenshots were also unstable due to competing use of the GPU by multiple Selenium nodes on the same machine. This disables GPU on Chrome, Edge, and Firefox to make the screenshots more stable across time, across circumstances, and across machines. Finally, this adds font smoothing to normalize rendering on Safari across devices. --- build/shaka-lab.yaml | 19 ++++++++++++++++++ .../text-displayer-ui-region-position.png | Bin 9317 -> 9204 bytes .../webvtt-native-align-center-long.png | Bin 9341 -> 9379 bytes .../webvtt-ui-align-center-long.png | Bin 25011 -> 25107 bytes .../webvtt-ui-align-end-long.png | Bin 24966 -> 24927 bytes .../webvtt-ui-escaped-entities.png | Bin 9111 -> 9260 bytes .../chrome-Android/webvtt-ui-line-1.png | Bin 3899 -> 3911 bytes .../webvtt-ui-line-negative-2.png | Bin 3899 -> 3806 bytes .../chrome-Android/webvtt-ui-size-50.png | Bin 12974 -> 12983 bytes .../webvtt-native-align-center-long.png | Bin 13387 -> 12736 bytes .../webvtt-native-align-center-long.png | Bin 13387 -> 12733 bytes .../text-displayer-native-basic-cue.png | Bin 4552 -> 5095 bytes .../text-displayer-native-line-alignment.png | Bin 4774 -> 5310 bytes .../webvtt-ui-align-center-long.png | Bin 36697 -> 34969 bytes .../safari-Mac/webvtt-ui-align-end-long.png | Bin 36409 -> 34583 bytes .../safari-Mac/webvtt-ui-align-start-long.png | Bin 36448 -> 34475 bytes .../safari-Mac/webvtt-ui-bold-long.png | Bin 37889 -> 36659 bytes .../safari-Mac/webvtt-ui-italic-long.png | Bin 41222 -> 39943 bytes ui/less/containers.less | 1 + 19 files changed, 20 insertions(+) diff --git a/build/shaka-lab.yaml b/build/shaka-lab.yaml index 884fb8c32f..331aa6ee53 100644 --- a/build/shaka-lab.yaml +++ b/build/shaka-lab.yaml @@ -19,6 +19,10 @@ vars: media.gmp-manager.updateEnabled: true # Overrides Firefox's Linux-specific default setting to disable DRM. media.eme.enabled: true + # Disable GPU acceleration to avoid contention for hardware resources + # during parallel testing and to create more stability for screenshots. + media.hardware-video-decoding.enabled: false + media.hardware-video-decoding.force-enabled: false basic_chrome_config: &basic_chrome_config goog:chromeOptions: @@ -37,6 +41,9 @@ vars: - "--disable-background-media-suspend" - "--disable-background-timer-throttling" - "--disable-backgrounding-occluded-windows" + # Disable GPU acceleration to avoid contention for hardware resources + # during parallel testing and to create more stability for screenshots. + - "--disable-gpu" # Instruct chromedriver not to disable component updater. The component # updater must run in order for the Widevine CDM to be available when @@ -55,6 +62,9 @@ vars: - "--disable-background-media-suspend" - "--disable-background-timer-throttling" - "--disable-backgrounding-occluded-windows" + # Disable GPU acceleration to avoid contention for hardware resources + # during parallel testing and to create more stability for screenshots. + - "--disable-gpu" # Instruct edgedriver not to disable component updater. The component # updater must run in order for the Widevine CDM to be available when @@ -88,6 +98,12 @@ vars: # --unsafely-allow... does not work. - "--user-data-dir=/data/data/com.android.chrome/cache" + excludeSwitches: + # On Android, we must override the --disable-gpu set in the general + # Chrome settings. This flag is not supported on Android, where GPU is + # required. + - "disable-gpu" + # Once the new session request reaches chromedriver, it will take # the androidPackage option as a request to start Chrome through # adb on the tethered device. @@ -119,6 +135,9 @@ vars: - "--disable-background-media-suspend" - "--disable-background-timer-throttling" - "--disable-backgrounding-occluded-windows" + # Disable GPU acceleration to avoid contention for hardware resources + # during parallel testing and to create more stability for screenshots. + - "--disable-gpu" safari_tp_config: &safari_tp_config safari.options: diff --git a/test/test/assets/screenshots/chrome-Android/text-displayer-ui-region-position.png b/test/test/assets/screenshots/chrome-Android/text-displayer-ui-region-position.png index aaabc0e55e2e69726b1af3f33cef695eb108fb66..6c2766b9e97eee4b172498420d1b4a49e7f51cb8 100644 GIT binary patch literal 9204 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 GkpBWP%tG}5 literal 9317 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 diff --git a/test/test/assets/screenshots/chrome-Android/webvtt-native-align-center-long.png b/test/test/assets/screenshots/chrome-Android/webvtt-native-align-center-long.png index d47c9b8f885405c00c759833de47a166ff9e53da..ef84bfb3532e97e492b5b9f6051ef44dd0145c43 100644 GIT binary patch literal 9379 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

|0vdCaw$l>h$mq1bfM?-P00$w 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 Tb8Wgg00000NkvXXu0mjf$wD7H diff --git a/test/test/assets/screenshots/chrome-Android/webvtt-ui-align-center-long.png b/test/test/assets/screenshots/chrome-Android/webvtt-ui-align-center-long.png index 1b612891a23fe614fe360db1607332f263f746b8..7ad9844720684a50715b1194b2d32c8cd49e010b 100644 GIT binary patch literal 25107 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%0A1Vg5r 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 diff --git a/test/test/assets/screenshots/chrome-Android/webvtt-ui-align-end-long.png b/test/test/assets/screenshots/chrome-Android/webvtt-ui-align-end-long.png index 6509c3e6fd4703d24b1960319178347ba470a2c3..808cdd374ee27a329a7b8cbeb22f8ffc6ac404ec 100644 GIT binary patch literal 24927 zcmeEtRahKP^d;`@?(V@YXmE$%4#Plz;10nhxFxtlaCZ%E!5xA-1b2sRe*b;jxBd2U zU-+1r>gww1s(a5p=Tx|=vJ5H`5fTIh1gf0uCv^x2NHO65dIUJ&@9xeGCIo~jo!lq! z&mNG+-S8gK?!8@`>sJ{+cR=B(ecwB*>$NHtg_v%Qcp|J7BJ=9QJLU?d7;EmzDX_2t z|9VHJ)L_vM3kV!NRAS?^<9;4|YFvLH&iUS0{{J`re=!?8|4pXcnDzT4C!~eFPd@GcG5JX7 z68B9t(8Kdd~9qj2XJv{cU6_FT922eLn3;q+U#%s+0{>@Vj4= z*lRRe>7vPy(Cs;(Xr_ObipP0Hi8kzw#^&Qli`seNU=IaBzd37lAz4A-`mrN&Kw;%< zcTT`Hl+719wfu?75Kd@AKfToY;tzEI5nhC|Sm%pQp7an`+c4s^vw}IT3(1@VH!G~o zp)LNG@9RWEvrYL@ZD?mOYBhwl*qC$wC2qdvw$^j)F8-@JmI)M2SBM`UtSmH0OhJ(6 zO=5TelvHULF=n@&%CuV=CrTkY1)tyIw2g#?g@jZx@Hx(tK3pz*rOhukQky-G0ZI0m zkvBb>d7;XLo3KXL_8HsdXfb-8yaC*EjClOFDY8=&>3FdkS|cr-?j+4W#*depC8fjP zz_-O}t^+rmF}xsgW4b|M=Xzv#n?BaFP|5+>tMP33+2TsK!4uc7D3-{l&(ctId%rqc zx7GsDuMKCh-U(YUGsbJ|UjXu(-s{rK!S2G>YEr>-w% z9?Fj_M>F}7t65FkKlKW=_}p;{DD3xH*93-&j#V~lw1U6jNQtX4K4b4pBxVZ+xa!nf zWBLgZ&z7nqOGZE*KVL27`W#-iYwvvICPHQZcm0Ka)|yAF9|`Nw>0vKV*@V>a2tW)%es;9j4YtoJMjCja0eC6VCmMBp}ZqVX*D--zigD; z6nOmJ0$q*6l|1_*#i4k9yHe-QVW?~l{K>}!4aY$|#=ofk)dYg2eH7`mR!9muBB7rd zIb|q?6jZ0Uxe_vbmQ5bz-{VIB!NtI^c;dzZ3AZ*5WtTww-jZI1Om@=(D-MbPA|zQC z5;{(LK%GMS)&OVRkU+7W1(zdW4lJdHqc}{*0fD5F+HGB(Fpfgdm0;c7ZC4)z$#La| z=b+u9!D9cReWjfu`o94cr8ue{BN6y>8~udK(o>0m!|9jYhQ#Acf;+W#kJx1m_0#eL zZVK$y;|NlmE*Jujk3uF8>X1Uk71j~3IKAwV2~321KrYUHyXtC_%ZlHDl*cMuxKF@1bmJ=m)v{{&^5Q5D$*bqygBYm zs8G1C&~nwUxh(n_MaD-|Rc>^B_!nL`$#JpH4_!%!kCu@KF)ZOh-pOno(Kq})1nw)b zKauLj%hnl}`Wj(<;TDA^n&G}F81!`=02Ggfm2xD&@QYf5*%t1Z5Ff(-3> zHrtgf8EtXvM8aMi+m_MvJBb*-pH78-6FkGtm1!1z2`Ut>v)ZNdLi-oqZ%vsAC541z zDt~}OG;7txbN_&q>nvojk5@Zi(*bRe*bzL zy*5&uo3C0n$Dh&S5n7m;wsmqc*7F6~v+CTNU+1fqv=U+ecSdSeP>AI<(MR*p=vB3xH=?n#vtv!rU+NS4 zF8RM_BflKA6X_q!nlU%&3(l9*a=v9AuUqvfc5?BV0$-X@Eb=ukIlTp*~LeqS!=On@K@b> z4@|}+98OR`TsNh#=VkC0!1^dZN3_AirL-)%wZZyL z_LwUSDRijm=i5ExHB4GYrXk)Jce0Ag1+uwRpQNR0Jub|s&_7}Mv1k3WDAnljaxK*^ ziJ_4j&EiTghE~I2GzezeEjvG$qBe^i2!w$Yfd0NjB3T2~pCVvSXFAf$?{^{017$P$ zTgrRhUQeZG8%8!jvL>wf+!Pk13*Px2|4CX3%UKvsO6{H%oe%x@@e8e|^X@N?sjblr zp~ThAwy9PdMvYpOIVR0~AW#`Jy97uf<2xSQQ_3eZD0L9s@H-!(Sh8pJix8sAbM5N!|?2^Xk za@BaZvA>w!6iLi{RVE6xjytoMOq#`gKbx6HQ+R`h4rFKfQ-NSw{J9D1F7Ye~23d=J z<8pJP9>rQNmfhPw0;R!f4N3)FMPeWr<2y!lw$jhU!*b@c;{(B*)!*T#>^^#2Gvl z^MAD^CjO?qq48j4YLFg6^QGQ{(|*2nNGS=wlYf$-ULabv`0OS_Bm25?Y|O_+tluG` z*3%hsD5!);Z2q{7GG8rcrj=00g)@}ecrhD4q9o*c9_`(OuPpxNeOXaySCRJZcxLW2 zdj0t-?-%$FwuadaU&A-0Cmn^DKdR>e`O5WRK{4e6q>Dcx78yN9^SX(b+v#w9cHxEo zU=`W^J^J9`TrPgMc=xB%NSf;~RbS>?D;88e9ttHnXjnJtGtm0pw|bkkm@`Wsbgu)9 z6-ah>cDN{#t|)S_KT&meMXpIctgE=#YGCOmivn zyN^G^6~03w4m|URCaTdh>Xy^!yM4`dd>Y7sJFb4~^W}Z651_kAtM+=aR+Svwh?y-{ zPec{sovb(4n1nzYHRjBosVO4l@s@ZiPk8(z$3l~^u)%~U`DlO<(ho^L_yN?w|IK##; zI7TDZHCr3|`|w~f)Ps$-;q@AiIWxP}PFSqY^f|MBN|{Cy6KEVU=(?m)vx(P_G{W)_ z;V8NwWFm6ZA%7x{#8bH~>~SMOg$DGp&7Vt=1+z43A$q?GC700vtQ8tdhQ?_E4brJM z!=#3fE|5}1mX0C|80!zsW3b{Ts~7Pj!xFusF1*+ks}agC2ZU#E=OhaWI0L>PBlvD(~W0+ zAG7PFOmwGPskbZmt1b?!pVz3`;%h-hOcoTepuW9>Bh?LVxZo8Hdr_JccMUQ&K z16pde=p%`tWTJ}*qDK#maIgKkz)N)}gSEnu0(-Xh=J)^bIqo8+mTm6f$KmWdBkC5MSc)FYe|i?+NVT{^$4XOo~GvpCW* zgJ~5u{O3oIJ^4KXPFn~E_mXyWE1>Z$f$P(ibYe^UYU?W|v}Z4W(s&_$ zpGyuah*VMOfX^CC?2aLZ-tHH2gDOKw0>pfFs~cwtvY3Y{+&qJSV%=VcHcS1G+2Fovn zatVTyy+*HsKcmej2A?qk3aOaKnq>CW8flmLQ|X7FBm3+@@a*9t1ksXg>joxaSNjw1 zm`TL$>cd^-s`*3fZXa1Bt&a--Q|vK3E5(JLb?`dvaKfjMP~3yRdCa8CE(K?U-w3Y{ zDaeGqx(*ogQyWc)BFfLbb!nMzmgkCkWk?TZE3sGqx^G{RWhZ7NjFvyt5%8K4@D59d zmUEb|pgg*rjFdPRrEq+KLMImm$}LWZE-@q+oQ+u3lFwE=dLZ3G$IJnW3oOZ6NGUZj zsLvcX+7MBbU$@3AB}Bt7IEu zO5OPZ;!H?L3zWpmW-)=Eopd%)Y5ck@y`XIPp2X9p%Y&esPnl7h)at<|eEmqeT0vC2Zqf4jaDCI+idH$b+m??E-n4x>|BA zPCI}`KCM zXoO`cavUIvhf?TsAh3=<)+Tqr-{z^=Fc{Qx7`wa#o|3lJJ%{biS{Xs7n{68|)zk_4 z@RadY4fM~2sM9K7a#94}vMwir74r2v?Q+gD@)+7>E7Y&rmMDNg$G_s|k=;3S0^j7w z?{bV0&;YHb>Jb9de5Hql_=j^_8XCDdg+*V{?usXZ-tGctNZRt!Wp(8!;kT=g66#GhXTd)#Y1sX z=WbdlM1nuFi(aDE4AJe*84fXzdKb7{?o~-s=x}~RR3hevCDj2T7qMp)%5;+Ttw!bdz~i3ZUhYXnh??|0~a1V4&Nb<6%Zc>B%amhPE525_bqWsN&IcLt;u?E z4WvD01jdc+&EBXQE`}eS7-(!n_-lPB;6BPGV>?+moNDv^r=|7nYTHdtsAuRdgaV21 zKwAFacl^*I#1OpSJ4scRHyRaDQ{}~OAvmC<8MNvNmg+$JYcJjf1%>B|r5|wdGm&-c zEJL_C>BP+>s7TY?DO_|IblYpim`sALamzOUZT)G9+!uo`-s~I3=D$9f#~)@9XM(wh z=KwDfa8k)(CCVt$m8odS!t(tj<|-QfbXI6N)2KxAQIRSWg>e7}M~c!iCc|VWT0Odi z|K8#*2-Gz`LX)N5+qZ;0W!=E?W-1_1y8}UO5{&eV$>HRjN3iL1G`)a8-C-#0BXa=+ z?^-n8c$R1+@Dj9>jjV7`Yc&hyQ<;38#+vwnT(0WDHkT5?GO}|%0!jC3q?dBj%K{|U zI=WFR`|)-YnCTqNIxQFbh0OQj?#l=r2@nz`uh6211<~xa?Kz<6tW>KY(H88DWNH}r zX^QB!H3StTXfTUnOkjpK*9sC2;?N@KK5+fm(dBjHGv5gb+>oCdwIxOhp9 zU#VhHF4eAgT7S8}^roh8t;jV?mgxNw+rlMw{|f3a#I1iQMomUH+UwaxK3KiR`D2U# zBx}>{(10YDI=t~bo3=`yn?r4GRO^T(Gdc=w2q4dVQp52bv1`ho`Pb}rPPDLHmDo>@ zyi^C?_j+~>jUt31%5n-IZF5uId_nqT7q!!!5C5Z7BjP=}*SfzMO^<%LKAXy>b4};? zdddxE&6JV`kEViDPzk^yi{kg|NQG}hYJ7ql8^W%BmN>; zO=j$}@95#Tq88^jG>d=9-L||}?%^UtV>xGVA4EXHmU-h20L6T5=Y_P(-uDuAcR1Mw z%{Y%kGHh+jcyxD>_Y`-vIZK*RDQ&whm z{0T5d&*=%mcqKn~xuXGc&^xK?c}FMP-Z$1C4btF@{}6A`;u(T(arvh&ypDbmvjrM7 zS=u0L9S$vnc77CYEFK7Q=2XyT*{#|9kSfd-&uYV4Ibdk9Htl&$xEMyGfmQX(-<{6h z_u~aK<_AoMh`=Q57+6s7ipSwnS zk)x$0JwW`coyW?@H9Ds&ZM}2%Wd?1Y(F@^`k<_os!oC8}Vu7yu^NuI;JaHyR?D_&u zj|kQcX)CWS0I|cOTNg}be6s;0O$tcPPko;-ylL=$%1g1m833TW@nmgaf8A&N_WKFN z)ej^pbE@H;pW!U2br|^MgFsa$wx!8gzFMC&vcR4{XEl77oCp9wEn6M&iGYs+ZvO~| z3cOS94ui{Om)m*I;;NonacIO1BeXG-PIV*r#!AALBB zUdMO4Z1?Rynau5SX6jUfD&&Lf3*?!~gY1}{4*#AR0rL4Sdxd__1cmQ(bwdEQy`w|G z=@Oys_7sW-fDb0C^R5SmH=v7QiRVm@!m;cD`WI30vr76?Fo{}Ne)aN6P9T6Owtn4F z+02*stw&fsJnjP1>Z`z7Hq~k+;BigygnkB(J8^j9Ww-LX8wlYoclTry09R&UV8HM5 z%<*J)7eExZ(X|N;yqX->sRW=pmrjhQwMm+6vA1L!FoX$rK|*5YtJnc5asV7UJ?!?x z*_!kZ;JTbF{G3Tv4(ij;TWs;B7pUFuTAoRl97Lzw3=2HB8}-Lkh1Po&MmB-`>>uNv z2)77HN^x~M4I#7vCEGp8p^Y2^Mh2+YCa%m^#GJ$sSA0;=3pN7EA*&RFfN1TKp zdiDOVSNye6BprzNo0R**PWlsVu6}`J^&>^i*^HgK*gx?2h`aG;xdcLcO&M+2552y{QN8eh&0P3kUWR~w@RY=rZ~cz z4O0Erzez@<-j4h8q^Bb7kwFErpplGd97&|1oH?u1>k}Gl?UJ$a^URz*6>s)8Zy%uz zeNIoyt=Sfh=Ly-3N=KQq(m@b!01VkFnIZ{qJo<=_Ea)>$aaZqHP)V-Fa5^)47y!l) z#qX=$EBM|gR2g*|Hp9-o&dgEK02oc?&$}~h*$ETuCo>a&pNy$E>yQC&wvA5-U7@L%lG(nFtNfhtKEbb|Cjuc+xE`sGZ6D zP4F%kC>juY{Pe}fA>Oarl~3A!gHH9U210l_FLNO`wjXi0U({!FCIEbz=+>R zmOK=xOWsYi%~+a{kMeR2J$Du!;K*yShf7bJsOe(BY@X3yses|Hu(=r8Qvu-v+GN{; z?tIo8YlGZ>pc0bU9t?#dMpVTK3D?zAM$-jB01=-23kuH20tUq&H4cJWN1Zk2eBnc2 zSUSAt%T?aOVRv5{ia%y`(BDG3WP3JFPcRgARWg(=rv+t~C`4ufG%~ve1ausVtUsnt z-Q!mFD!IBRAKkgr9To61Uo>%wXDT8GgchIxq4@tyCZw!$2Rl9ON^>fh>|21lAanw_ zhf=BO$-L0lm)+Hil<#)?)mVi*f`5+-AvZWwl=Z5tm4F zW3-jdfas818f~kd zUP|48;IB7>LvnD)k)CpuH$k-XvjxD+)O*K*-%= zPn|fw=>4Dq z-9yF)$pH?l0}60e))?1G&|fb50b#gUqETQqdcF%9!DFcATlL|=;|Q=qvz2=3j=h6w zd9sKg-2o79joY@~W9-2MAVkMMz&lU1_B2)k6wRczSzc17#op zEYL{!yO<43jw&laV;Miu*WUaseT2Ui8DqzpEEa=TFLi2eQ-CnWN?hYPq}MWEgXuLG;3 z3jKkUVe@9UZK4~SS<8i1!)E!)0*xH^<+bvAM_9W`yQmD#giZ4>=dDr1)`qizgj9vD zQ4Oqv8?Vd#;fdSmWdQ)un-@lzK4qQYjOxeDMQUwto_44IU^7UAUPf0flV?q;G?G6k zP;ET^EAa$AS!(;j4%ACsrrV9t&8^MT+{KJ3p2`49F%V7Bcei)kx$7yFP@Sk;HnmmhZaEN42(yDk0eB;tPS>EqQFtm=f6QHJ zCk``Xn-@h}^zC2*AY{Kx#JJ}CDMVJbpsr_hiYryXjqZ+Y#k}txQ}NAFPzo83)<=oI z9~ozmZfUXEf*P0_B_iHUDOcd+YLn5xpqWaTgzMv^5SyeG?;{>ySF%DpDiinQo%HcQq)-P26_1 z19w)8$VccvUjjaab2A;$<*^<+%naQT2+wJ=_JKfGAO%h|R_l5(fGg;4#a;aB21sX9 zQBpcAcueyZLm|ZYVxg&`<2yZ7_ykX5I=(vB&~T9fmNA(k(k~m2G_>>qNRyXL*w=?s z@Nx+V)}(#iT=3$7h#K?`r;`GD@J)q&R(_{zoeFd4Wz%go_Ect6#n=Y$ZS!cni-awS zq-Aaxf;2zyR`t)X9n+}K4<^%@5!V>cNknFQ%<{R8N z6~sXym9MvF^|qmLowhlCw)zb4sUE=k#l1dQhi)^2=ea(eO{aQ@^fBp* z!Uld)_cTiphD*q^&O4E1H+%E-?r#*3ywyW^cw@%FlG~xt!{1l!EO$$P^82jZnpZ<3 zaaXPrgjL^|=1@rjg!X>;CL*deuRk{hYG4{1CO)~$Vk-yHyw&&gHPo=QIctC!TFz?> z=rdMU!y)l${|1CTK>{q!U@xVAHRf+mc_o*)4Dm14(24jdY9O;la)q7 z&rbI>4*e3q#)LpJ38FE_LdIhi%b!y1uy!@#HvJ2eU@NzQWaY`)W;WQ(oQR(yXQ`En zXh*J?zZWelr`(-uS(L>e9D~?jSsN7Xf;okm(czMm^Hf{dPuF3{=MNUrAOKC%M*J{w zAGK3Y)R3c(AAf&H4|#YX<^8ftY&B?i!vxG~dKF2UW!js0&Zd*+;v|Bu2%xO8&!t#s z0O@0Sc`z(1EBr16qd|H?4aLDkYO{fRiV=c2>Et;`k*Nfu|X9RO$@>Ug^2cf5u13+p$Hd??ta z_jx&7n61!Cb|s$2bmfnrE{ef$=SQP40#=%A`_9UZGw{%B%$H<~5Ih@D0lUzLe=C`R z@~EFa5xtgX``^EaAR4)LhW?Zu`=xSTl36C6DviQVgfwzg0FQRy5k6;U0SJxU_Ols) zeCvELOQ~hAKQ=^3{m%U`^Og6lE@uMpgdeEG7wnDUd2m>baKa=WkUx0tfM{s47}W}3 z&|oj|{SmS>j*;wlp)|mXlmPP7Px@*)GR}Iu+!SkU=DRuiiz}nmE5e1B;my~Rif>%ctVB#p7FV6#*<$C+sELdVZ)lTbg!q;Tw>(yjst4K&V?4L=( z{>(9Hw7WQFsi~fiokmKA`_S?`{DYVP{4_>+kSgpdtxYG&WgA-W(p#o-n7q~|#R#YD zGo?HE%B~dok7o$Eg!ktF9vUEz9#y#k>`3K4zVa?}tv_EX%h&Ncc`5Iv0)pGEa}OU2n`hhu+L+aR^1e zz;{r+V&AEBFH-$20r1AF$x=4>j-rPm6M%HIp<3x8@aHGnpgm(mVB~zrf@j>L|A}|w zOf^_C0*66@E!zNC9d(XJ(m;kC0x7}^HJugs-aO8h8(=r26S?!bH=g_*NaeDu{#)+z z`H0#q&%9XgH`7sL74=*k649$u6ZvYP&+6s%zv)Q3lhzN`_Y5SJ>+R#!YP|@{IB;0@ zpt>bM)d5(>04RpZHbZ-`N|sVjFO09z0~at!{nj?(j% zW#tr1FaGr_5^{ya28x<>r@_MTp$=>g?urJ&EK)cZj`F*FnG1;m_`k3+c>9FmkJwY` z`HWh{1c0FltZ`2Vu?M z5($MjDlK1*WEpc1paQO{m?UvlM|bxk`DiBo@}-7QOJ!qWrINqD4i+lNzos|+((AX5 zGAAh-&&*q|_WeZiU2LrLbDiB71F!>fp(PR1iKSP;uHrJS^r7_pQ3RraaZ{8O7fh%d z5(6LveQfD`y=beMYE+}8b_ampBL}TnjaBj}f;lzIH2Vif!eqi@`K#X`w9{=Z z*!Rbf3ISr~r)MlkqE}wTaKxw-!9dJ>={PQ9<##vQP%gEupgW`c=?dl60>av-3ia*N zJ!ODmi|YdL$VKjU3!no_jo|F6{iTkBB*tM^&xo*KzGS1JG1>>97(c-0ULrBS?-U@R zCtSk7OI1`m?aG&G70b`GDwP=32?DlT%_FUN<ew#>|Sh6%Rf<;{`7P~;V6fYgjgEbOSLx0 zfXA4w%w9{R^a)d~Ms3B*0hvZDG&l^Ae}^qKJ>8LSIF31o${gwXWIEX_B;te1vFd;_ z5i(l=^MP?(w=v3I)%E>_IZ3;4yGID_<=%MY7?`?0B~Wtug(lB0x)89!GQn#N008{_ zWHTp7NuO^j{~LO#cCqr@rRF=67(N^haI`Rh>`}Dt{&K*VLk=5(`|c#8hKn*;NHfG? z(m+V{qm---xG7uUGP^`@lRhl~dJRP-fODIcB8lnBHGK*F-}>GL8dC?7fk!@SIxpZ& zKAbK=zA2mAzfavZi0T|#UXgF^KfEd`F{%-Kw=!AxGLddh$v1?!}WaILccln1q*}3CmZb;gevmPZ^GKp<0A+(5=4S%F0FfD&n^{t0&a0 z^+NPrdKn^*%hn{;4(QWgvgLJ?J}Iy*sRiO`4PX;dO|;YB;bp-?Mz!Ik0c=h0#(vh% zarBmC?@1)q?V~CqQ*|I5D*2BGh_L00Ch@HnbkX}bI@C0ZCE99#W3Z_7HzA}jO=7K0 z6WI?YjVUGi9c)rpIIzqI^@5LXXA0Y`(T;JNoD+b>fZUbql#aN`zQEzNCm0P)irS_N ziOm{+Pcbv7ERvaPZwxS0ZKnc85n^}S0>F;%;q6st_JTBdv9gykX3*jIa|5p10-GHvHt_lbmPZ5f{Pk};_I+NfBK>5s41OBFcxHvI`#wi+2z1LPe5#Cc zcwO-Xq)yF9EdmQ_E7e+6xd9aNplB*)3J*@Kr3^veh-g#dl1FvT$J^6LNNAnzskQjS z#6oI7&-Kd$DzPCP9I{{xsLoQ~;1i_n+mq$Rf=HKlDxz*+4B(M&D36AzBv-YME?>0Q zuk2pj#i7eh)D?eJsgk8Hrs$vu?^hah^z3JfSlXOx;f)!5`stLX(wcF=&jFp%Nc@#PD+c*B`CV z_kEFEyb$P}3SD~ZY=2^)IvPRAzprxw0-)ZuZ}h6Te9t}p`b>wWEE4#1d}B0j752+| zOJuw%^#7FfqaG(o#dsXhB3s;Eh#E@gsA3h!=5397OHs?Z5EkqWEdQR(988tKKQ*3i z17)=g@wMWP6}eW)5Ki3l@w2h%IfZu}j<@ahEN?yb zh2UZp!7c0<>^^I!uC89JRYFAeAbjv3sS-DoU?yiOz5ylJcsz93Fw&CcK^g@TaK9k= z>fK;*I^m3Hi1{b0_~S~mYf!{4lX|fU<$xkt5JsTEFo(q}&R?JTP`j_KQ`JV2r!;H1 zE*H~%1N~;(ho^{Gci8@Y=9ssE%8;1|s7Mx{-_+`#i)m}L%}P{Tq1IsAb@5wc9P0)G z6q6LR*&KIvFpZe5umFezAKr#i?KNYq_iZ-f-I+^Bh#0eC;je7$P9@Bdf!kR{@y`M0 zLVKH0zm!D^8JG4_mF7rdA=dc>Akx@pQ#^ghrDa{EQPVLd-%QxbjVw?^xf?! zM>zX^A|0=1)wIIO;h-tHTNL)cM@LE_1SED~1A1C>s#BtX^L||6FSVgI44}lJ*wh0s zxk~Q0iCdaq^rq%++}j5`LzUm!zDLAt86j$89{|+{ptOKj*tffes0Ex~QTiis=^YFy z^n05EM-4ewn%$ry!KMSpgnjE#^pXBsv=Ppi6NxbP2-0((Q6d6*L_*$EE2X}q7-W!H zS6dFBH~Ogsa6pD4J|75B)m9f&(^7){-y$^%R52@!I{zHg);;7M;jbvSDZxPoJ))RB zt(~|W%mn~-pxSR+&&oby)2*m*m$ynG2~1F&N$(yije$~*zcwV0_W1#2@#F8a?$Ak8 z9Uf-CjF+H%`dBIj&VD5P?LKmPgf$ElxLS`^&jdRq%jL?i8G?QhD>T38K6tO$vXq8U zg+!{BJA4>77M@sSG(WsGZI}w=o?}p<%kZ>^r-$S5 z><3_h^}0)TN)830Ala_BWL5|@B@AYS0nfPk@86%>kIRRTU$v89*`Y%^ha3b>InmJ2 z6thJ$oon`oq(cv=r^;8VvFK&!fm$J~sEr;z5B+?s+CGK*8x{lToN=Rf_kQHP1tmxcqoHkD3=)?P)5Oj%>a&{<+OP<+<9PH0U}&p0@`b%QuD8@Zye{jwWj@4n-W%)A(*qnZG`~fDKRdpnOTP*ytU-I_=Q^@0%~b2K zth72uPHD&_TFcRD9RJio^1wA2uNC+tEfc7i6q(Fk3+l(h$(JZG`^B(h_+513ZFomF z@epScu?!@YM-ljTRPGPQ;NL^-eRR{bSnUA4`ul7EFg$qL=|Vyd`AfJleP<3liC@0( zn;@s@LX!0lSSfkGVAO8{$;uy!;aRBM9|A{gZ=Di?*`3i}@f5~nmkpZYVgjM-k0G4c z)&;_U7ZvsXPiuGJZUhjiEO16JaDY!UV{9A+iQtpE6V`|}>wXJ(V@l3HK1>55q-e0K zbE2zL1u9CI2$AFREFOYdMH%>D2$zKhEx?&GGH?t6Z*N7v=RZDeKDbyyMFRs8f~iB7 zw?TqQ3u=s=5BrpClrfm1(IzYPjwU;AY>0SptUK2&GY2m0MB#x5E=#&CBmT-oPoks# zr@nA5f~&}4(nT|eMyi~GnaX#82|!=1_&=hQi)K1Z$(S`@Wy8 zo-J`kQMPpR#KoQQ1MudAduMUx(%_G5Kj~CwE?KH*Ps5L2fkbtQU;6NUHd$)71q&dn^Diii7Zp?%WhtU^*|Hbp zA{LkF|3jYsa(8Ejt6qa}#OR0eR+S9!Qf#;MA2WTTZBkAbVo}iK@ z4RI)#IFuw1GOyMg(y$m4`j3PkP(*hM@bKR7?JFG)90Fp3vC0sKaT7e`K(31`$3h@e zhE0G(1}qb{vB0errLlEdj5*_=5I6`GJ(@iMWaat zgS#_4a!Z}Rw~@Pnp#dc-h8SnuKz@z?uoYFOj4z2&j0vR>t}NX2f4v}_Cc^>p zfMJe8(Lig}&iI46B;1JNPzvH{Z?u?n6S~uEfmDS7#Uh3zpa2it5SS^6_h-a&m^g|7 zNVx_ z_JUU?vWxu_%@yXhn z3COk=FV$x)7=8iX9hyh1p||AnsaO_bfpz%f)AkOc^U{EY*5Ky&Z(`Po_cUP0?Qsvr zZlFifO{yumav~j<$~KqTK@+igBTQ*lG0pA?h7YYXKSR@V`+^9^dB1aIdL1{#?NI?4 zgBDXz_zSC+C-^MPcVelzPWU^^@ca1&BSY^^jY)Xj1mLK`c2SAw2hVQMXC+#`hOz~4 zcRj3P#)tUl%7-sYd9=W!0wQ*`!=c1)(i>LBL&n9FW2NKO+GIfOqf<=l3dY2CaC6%G zd1plV_=!6q&T6TicKzl#re`grrc^5rP3B_E-~PKWS$I(xJ!SwVzW~4KmHdr1zxy!> zrZ?3hc}KPpsaO004?8bc;V6XwPwM=t-qi&>`AoH)d`TMlD5<|4_B8x`xK#%{O-6 z<2Pzw&6hZua1Fn#Jiz>Vyx0j%Q~S&qW zDjzwk+V7BR9BV)r8`|BmlG@h!}Ifr>FAUmqE%A7f2MgFh%5 zaTC&Twr}3S)zOcEpY69FJohF*UJZZBM&G`QI46%;bQMGTtn8ReqZ0J@g=42Sn^37O z=M5$Ek&i2nFJ=gN#$46xm)tpiEXQN!O)H#gRyGgy75#xFrI7Q5=n3s4UqK9C*-*GY zh(RJ(Ki$sdHIGXK_8Tx63d!srz|#a^wyf|tSWcBlxP15+@a%>fVAd*p772k3KrRMQ zrnqyU)uXZoXA2Ngj%y@zRG@>4PU#U`Ab$A<*%tou2+vzeQk^m=B6wU=> zAh0`AGZd9=^_!wq*4~28NjDYKc*2Jy<9(*Du_b~e9UYx0wTYrmM3dI(o+}E zqtR?)%Jj3WFK`_%hXJW*B1?LPySl5oD(r*%r2&vx6d%4JDQL6zcP5GEmPs%k8Ya}& zbI;oujkK~JRkwJ(Fa_8^FE#k#7rhB9ZTuA*&kzb4JMCygG$5Dlxq)evu^n6(Ohy-d z#9#q2>gLf@&HMZ;Td2Y!$Dg3qFcs^9z*98z_ZD$4oJb!ZmEyX%JU0V&>Ge}7xfO`< za}EaXh$cv363<|i?H$FvOg+7qnDeX#VPzf6sn35NYkd0w{kH7W!L2HoB_jaXibr@= z`JkzU_Y)%&Y|{8{_KQkovHFf1Ly+(9>$YS0Vdq5!0U51#^*APacr6%s9YE@MHuQ~s z23{3#dLebK_yNwetkZWo#V`=Ou zc7MzknxR)LG8}PRB=C?&DGdN3jN{=STBb*B8bf(_R6I6a*}lIBaJPiAlm93<5}3Wc zy`k`dM51EJ0r`c)b@sDh(~;s8dOFu@(?w2Cv3Nd%UNM6x%1gjzCki}u9NbIi=|r4; z=wzLO3S1PKzon51_?0`+hObgB*9&%QdP}UU-nhuoG{LM ztlQ?m+6#|bpC^U4y~6DSs# zIH&|Mh!hI&#z53LK=;KR)p!i@mB8bUHHKUCy6`vz8dZmMPSF(KAr#h#5Pd z>IKZg=)J#52htjB_^m&{rbz}aXsGe_w|0hp5vVJJb#SI zQ#go(p=8-(HbXG@&64Fg8tYb1K3Q2N9eC%MJ8alc!kYdKQHna%>B&@G;OPf}EWu1M znn#Dch7T53sM)W_$2wm^ac7W6b^IKzI4|9tYNuPIy~rMLteb6eKjHVTIpoSQ<$XSQyl~!GA_WCURLjPv1 zkUc5osn;<$7kSGdSomAyJUQsfLOK>4ggIfCU<*FSlG~bJW7Q(h&ZfB* zf}Zca8ZvuzhlMs@RoyUh|KH>eCYVb#JmXqWRZJ%JKIw0pK_0GLLGa7S7-VHNa9L$s^0u$J_SkED@~Wf_STmj z-+C{0ue}_G5;OL`>f2qFx&@d(-;d|QIf8=TI_carhB1^G#XTF`_3X;wSGVpcyT?E{ z1r&fnl1aXHnhlZ;uRnIOP zNil6!hY{tIiFLe1+f(NJJ`FmURaiJSljGdgdylq0WXAaD#&LK5vPjbKd)Z4 zkR%caQR)O`xq(45gA)^nPG9)%ss^VNt+#-TeFT>GRO7%(rBU+2gWfLVQXRSMhx@d}WGGv;;H+){K>I)*%G z_`dLHL#9j4x9grv4I(I@(kwIwSN`f_4IBi7GW8qXOsf4aoAj3o#$Z{n>l<$j!dq8*!j)wG0y<&Gs3Aa&0qZAoA}sgS2bh;G-v zZ@(Y~G?v!YU1c#;F4z3(Ku1|q^)%v@^<;g6+&4$Fk5&Lnb#?n;D4hYf3FlA%p}`4? zwH=RL{BJ7Q?NvJhk+Pn59qaJPxzgknxq^1`6&HfakHNSsl-+xXS+wU{ffp7F5X;E9 zUw7^5{wk~Rhm5ysIGdW99f3aU%}G5=>Vik_=LECLyRRgLBbf5udTUY;GtTO%0&rti zH{(fGd}^2bl7=9>#QMxt{;WuJP5;>db^np@J7d8&`0aYW=%yGx^_M$7Po6+WA-oW+9WQe+++@XU==j2>ZDRGoTSjruSd+qAP_J8}jx)E+(M00(`{>KOnbx(S+ZIT9 zgg{(x6kzP*w8%l3RscFdRZ1|5pgUOUz`rUc_8%qB&@7fc@6lh5NdRL4#la7Q`@z2! zw1Hqhl|$aCw}?UBcQPLoJjQ65!Xg@tz|$ImG-24!b`!e1&Y)Q6gImP9s!!DMA&iW4 zE(sp1!fH@AIx{OyW%nn6tFMZ9_jrdrQ(OQl9C z>fhg2eiPk5V)Gmz%k}R4{FC2aGQ5#_oNq2^pA#cVj7$4AD(3qUReuGkiwb_xB4ED| zNdch~pg%2W!pJp>2M8@wu?<4`GBsADWakY(q!MJ($s0mju8d0lB*?f*BrrzUAG0T4Thyd&$hFj^5zLE2ne#9I1 zNmS$YA=5T1k1}`x`2m4c4S(}XW4~>5_wZ0eSmBXebRjX5k%8ul-jU_s@*X$tnKwR6 zz7O%jGY_7T7u@_EKZ{LC9WgTM65W3JsGHUWgG0hR)g>T~d0x}Cu?A^Q zOim3RRxNzN)XDJ06RF^-bG4xtt|BsP!|B1cvF8L?6I1ZsK`wM zFl3V6@**QIZ#q0Kgk#C!HxUVrSw)y8Cmsl&bEs8?idAk?exui#YRU5tKlI=a)-GaW z{`t8!F1hKl{lh~cMIuzR&ZBeZll_A{->Fi4x}Tpbdor0|SItVO5!cKKm8T!hbBWQm zEf8(kuF`;SNx)fk!~voaBxs{Pf0jzCxBSDXXO4*1s%c;>9qY?4^*ePNTV$ z{2{o|A~2>?UxX>%iu_BO_?DYrP(1$06Xw&i(_PWcp3VtUY~a6jAE#BPO7oA5bC$jv z;|;e1DK|-i{cz(l-e98Y92mXnI`UE`euuVCXAt#DKb!EzKti-?a}iAk$G>b!ru?{Z z@tFa)($k9Zs|ql0oh-qhC)0g^BH6!DpcHj1udB++cbVjb%=o>lj}9%5Uh=vG!C?l# zM1ZQ$01zR{R!=(g)PbY@`{S`+DytW{w-VEN%FK67&8w|aqY@8fewLd+HM|YPy)?h# z9WiuDZ@1armj;`SS3?1i`(yoA9)K1>W2}I+k(E$xb~x+)EB>N6AAfJT*EXpbT!-NL z0bCVYG2w}q(Cy6nf6(q#h?@Rysa_Mn=SBSyg0FgWrcnU2#joey?n!$l-7ybj4)U57 zx+b0k(rY;)-GVT-h-Al$FDJ^~!uJpR;s|NY$uHvBaB;zAz!a&d7J99hg{%GEpdUF=st zgDFmH2PDdTm6ET+t8CArYvfq_+a zkPuiX3$o>%9m6k42m;LWY*kV&a^CMF_kl!iO(y4Wk_E-*Toh=EWn4njjC-!m%z<>3 zMa>;_iBN0c8l#xSYa-G^nb|x-iZq!p@t%E4hHT9V#DwjyFE8QLXH8wgDo6AIJCL;` z^k!!!cYk*Sn_A`}Zugc=q=~67nYrBI9HpfVn<$C8>{QoZ;(0AGjhi1-zkFsf^AwBG zyE4vQ)T~nWBVrHhj4N%0oFoUNBXNF@PURug$PA&JDk;Pocrx*O@0e3g`-txLyln(- zKzkAE<>6~TkHY`?A00V{pO0hM_uXQ;?~%{6`G`FgGcOCxT(NEQM|XaSE$UpJO3aMc zB5=uIB{lS(G%yzuii5a0jg6Ok@d8-i38s>oo8BA3zxP8c3oy{ z-v^|+3_mleFyWaa_Pa+%Q|o^@YP~=U$1wzZFKWzAx`-k^FoS9^a#x1#OVx_yX!>m!9RnjP z38OVt*p==v_kl+eoR87Td?Fkimsuq{N57{6LUpNNF^{k(;*n?c?x}xr?+>jsE+v$f z2E-^wQ15CZO1-G++J%sHcBTtEd}>@i^^yrQ86_pcj6oA`1lo6gF_59@Q6hlXZWJt~ zq=8R`a)IK;S6p?Cq^q>z!aqtuVzDl}3p~i@(t~7ZK zkthB-M(m?EdOi}P6SG{{flg2!JjNiY+~p0pdR7RrXp#L}(D=?O8xzFSi`+5~K*ECh=xC1UtFj?{O-jD{DvNk}RZ+mBRuMjW zP+66PXy&I^m87KP779*#3lM z5qDL=P*a8aImrjJLvBf}d(c4GRg2`OCv{&20Nuw@ZBc)JO4)e)jE;SL>%3$8MqQIk zq`-h7_o}tfuq>E&2{SVF$piY1PiNe?&;wm*p9OiKs)4De6P;EaFXJ{x(6`c z;&o9;ME~F>fmXfqf77ZjOk)Gp@wO(?auk4f9oZdO#ZLQl^v@0FZDJ;%yEumNrKjYP zv+Mdc59b-Z+MWWgf&{&RA_jkKuot+GT%sej1{w^quFLA{v;0L7b0ENQZnAy7{q^C) zo`qKk)UF&H8fw~H^|jL*U7HYMh`St3RyPumWe zzo**`eppTZbnQL+y}BPpQ)Td3`o`E)l^ZCnG{6Oazp!Q*GB2`BwEJMY<#O(`Hk921 zP`INVKh2g$C;RO^rC94S!~MFSKL!pF#f3%;VVoV-i{xN(L{b#?MlwgBMJZexXA>%l8NCF!sL0MbDpyol$d z)OzuF{bzIajBQH0F1Xl^;9{2!Bja$Hg!4#-49I|>?sDA<%1?U{BIpE%1na0|IQ)E5 z31G(*22!0Rz!asnBR{=-fT;kj#%g)WM)00bTE3ztZq3SjWo7m8O@`6tyy-!3@(mB? zE3DgvNlD55aerj&qBnwS%WV6~HtS1p^KUTr1E)jTcnMs}0(PuW#p6OR!mjo}w#y5} zE+0nEF6jSxshK>`cdj5R@zA7BPwjsBVt*NKvk_SG#)VED>y)Ktw#8-4yYD#IpEr9e$^~Cr^!t=V$@rf!hP|B8n41}hPK$1U5`Yg zE?Q$pTucKbkfvy$T#Zd7Lj1<0@3=ydgoa$)bA@n@-|`WO3sDhf0C6fC$?bltHrGk? z{@_>1KiK!(>MfYDAN}oU&O7%B$0?w6RK%yAUD}Dr(yTUX%e&jU-+(Jld>BZ|$>evk zLgh)mMNQD={U(nb`1NNFsr+z9(ag;NOoOnzPjfL)ut#y~EQ)s-kZL#%9&d4gK%hO( z?fV_3ew+zs+tt*T+;75SkDwLcJK~r}_H-R&0(CIdQ__=-k7T0)AUgeE<&*;JMu3kQ+ z#tZooFbo6c(x98|NJb}j38x3}(5tdqXJJ>f66eq@SZqS;<(cONBd5+NagY{3xh$AS zTPA&kVY=dWh1!rD6r{YP_)u5Ld~D124wv7t?cTEuWB^|w1W;tg(zm}}tye+@9Hj9f z396SJ1GdK`GD5|3$6JH`u^y}KV=&!z2@UTsfr;XbMmqfZ;86gpzdT76segi>p7u)Y0`gnt7 zS0btqN*=T)Vm82m4#0 zJTht1@&LRgmvT6T;LiTWi|DLr2`OIr(-?&p&BflkjRfvnnD)hEPz7E*JQmG_0e_R# zt=s=T%>|tPd5~ReOGQQZWZ+36EBvl;PaV0`(}!pfP)eKu*##ylVeMbHKkwJU=8WbD zq{o66o@c5bUV10t8ss$%{|QoFyFIBfc-Mvz!{~AJ;C9v*BrWev1D}p>@-@>L7&jw- zFvoZU{o3Z_+sj|BS(ZlT>;d%y$c<$|`(JCUTOWP9?j;AreL(G`3F16pgx1xr_E`2( zI*%aIi()W_WLc$Ki7hH)Qs~aA{qPGw%KL3@@+lwgi~u)tb$)$KO_GrN-;14&lL#s3 zp2_e6moT$4;wqKHOjDa+^_aR2%X{6m|d`+X-q z+Zw3Ys7p?6Z=5^RNoS%$Z-70__W~hi)!`C^6``ymp$bi*a~oB?kgSS5QTQ^XHgkS%dHv1R7 literal 24966 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 literal 9111 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 delta 3305 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 diff --git a/test/test/assets/screenshots/chrome-Android/webvtt-ui-line-negative-2.png b/test/test/assets/screenshots/chrome-Android/webvtt-ui-line-negative-2.png index 9aab44456e2733365537c20b17c1295cbc3fbaba..6a1c293386f5684220b121d0b4292f234edf4a58 100644 GIT binary patch delta 3181 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 literal 12974 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 diff --git a/test/test/assets/screenshots/chrome-Mac/webvtt-native-align-center-long.png b/test/test/assets/screenshots/chrome-Mac/webvtt-native-align-center-long.png index bd8fe6b645a785f44b03f580d3ce2abdc10ccf10..9d6cd5bf35a33bf2fd9ca568a2fc0e47983eac1c 100644 GIT binary patch literal 12736 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 to-b%bry$g0YeNxcvJ{{a0?^N;`l diff --git a/test/test/assets/screenshots/msedge-Mac/webvtt-native-align-center-long.png b/test/test/assets/screenshots/msedge-Mac/webvtt-native-align-center-long.png index bd8fe6b645a785f44b03f580d3ce2abdc10ccf10..da12e3396efc9d4c099fa5cf2723cfadccd35f2e 100644 GIT binary patch literal 12733 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 to-b%bry$g0YeNxcvJ{{a0?^N;`l diff --git a/test/test/assets/screenshots/safari-Mac/text-displayer-native-basic-cue.png b/test/test/assets/screenshots/safari-Mac/text-displayer-native-basic-cue.png index cc8069a6b3f79bf7d7cf3d0d7d08f284b3a0e6f8..a9b0bc02c1e75844ae5038d764ff8c095c6c7e3f 100644 GIT binary patch literal 5095 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 literal 4552 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 ACIA2c diff --git a/test/test/assets/screenshots/safari-Mac/text-displayer-native-line-alignment.png b/test/test/assets/screenshots/safari-Mac/text-displayer-native-line-alignment.png index beb6745e29f6cfc47677d5720f836f0bb8336139..cca929f4b9903cfb79c0f528e18f181dbd371dbb 100644 GIT binary patch delta 4712 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%0DP+bn+^+exOA!+<{tmMt%#~$;vnc;rY-Bof zc|WqgtHxdvtsZOp*YPRUeUE;fXMMKth2)I$vhu;Bq~mTtzgVtna41{)82Rg`fKbKA#+cG;$4a<`BWBu_%JMizk#YV6I zvDRpTMCy~?Z=v+aVET%QeAY4z%vSGC(m+I-2rW_MDUI^&uQT7%PNgpO7+6$T)PY~L z*cXSBla+UWh{9Zq_iX^DKtlI$tS5>5cpt}eaCm6r=i6$&+b>(Nv?4O$9u&Q-44kq^ zA5Mw7pV)IxeJK{>W83~b*XDEf;l|^3i6fR8Fl)ot&rHC9-W+l5TwSq!)E`h4ZLyrV zG#0Ni_2gkI-f!Q_r6~QcUYIS}*=8~WLUe8ci=XBj5)lhH zMEM_gsjuu?oEAG{_M3c|SUDq4HVkTH+sK_cxHy?P7-I0Ohdnngag)C{D$-zpr2(x8 z60XdFn&f@n_7^mQ;uYRR8GQ#xSv%c zzb{R138EO&(10ILFOXH=2*p%CCS!ju_^CJ7W^nrY#b50F-m-nxm#BjWKal~gmo)7>0 z(6>-M(X;0@RjkC8=p?RCn|XhZ_guNqmN_7$a=+btrCv2tBlP>t{bFg6xKO zA__m{aXr(Z?!|e!@q&@sZM*0)g2JJ(IYNr~bak+nsiD1I&`LGddHzd+59>s!<<5Da zNC1Pjin|)M;M?JcoKt5%+6+2;S^Af5eR&L}mIsrA!!A*&ST_y#umj%LGRsl)6)I6S zPWS##|7f+yDLTwnjtz{EzxBW5dhpYN^8QADd-~H@kfy}oCVqyNlg;lYgNu3Ug1r+m zd@19>A9PX4I;%(i>>h1?C;1%hcgK#f@I%$Nrw3=uZ5Ic{6Gff0*XPiFoAHobdBb4T zlK8&)%Y<4Zsr2y!Mj4KXg`IDk7f0tf2mJn{%Ip|DMH=;g0et0@ek7&*ar`rfDsR!8 zp>BEI`P9$&M-oVYcTPEIJg~X&31H{qDze-mYA2(_;YnBvSNQPigQ|uJ5#6shpeRsT z&4QD_hvnq_Ywr|yMmpOFcI;C>JPwu%$s^Em_44!D$`7?pcNR>0ua{z(B*;R(6U!ai z+TWPMXy^t`g>5`+2gH3X&vV;vwx63}63_)6`c6oZWN-#s#OdcD?|zH{ph8$Tfye=dU1L89bD&8cj<`xoq>%v)8cdP z7sf_8S`pM`6_do_bZ`9q0;G=D6k9wzGII6I-=HN}@Q+L#7$YO(1S@+!`;Eg?C}5vR zZ2K*WKY~RRNoRXlCUJkZ-I-shvWg4mF18z~vZON#35DL1uf&>NeVCZP921MiU|gBg zRQmVLhsu$PLR(4qs=vvfxet=-s+sHg5uPG-d$2xSWudOmS;zYVz*+NY{7T2YXf`#I zkS7+91H=_DZBaal@9nal)U&RA+k_ug#NQAZ#)lJ=OG#Yt4M zFgSdkz8#;a(y*S0Zs85^9l_bBJAamQU!3zb*m!w?`HF1_n;3s=o6AmQI*r+0hF5rG z`1j9fV>9FaIzr<9LU=}C)@aJCtJxA3tXqw@>BT$i)H>uef|GdXL-Kh+#b*rbx>ko>+ks7#Q zFNf)3{d<$!Ki6*b0>xp7#de8ROLR;^V!un1Cmq<=yuVd9{t-Vit(7D1S4iF?pCu(b zJIXle`|z6^iSLkE+^{dXGr*=yy;sMPx_!_kqyRG~2#qQt{Q`&d0WCZDWf%M1(TatFIkz$Ht z+D6Zv=O_IpWU(euxh{I$U}UqlbF zgP0ZiNvTOxEdm)EeQ`p~k}Y%$%y1xj&~C3D$Uv~v@Z%S3PwY=WIvF)4Di-qE9E2WR zx-7diexAn&?jo{IdH&*)(Uyl=p;+o%mVT_CgbUzY)oYKfhqZSrETcrd&dKN&yk+p8 zMyn*gGt6ug_1YK6opk}xt)f?J=bZrAC*R&!c3*#=&gkZePKz8%tS*<~TT^Ihn%R_$ z@^=A@2$ylI{37k0^2L)tABWjb3BO%>ZRRSqTc}-{Xc#Vg|H(jVsIc$8gOp>Ywo0wh z8DtM1)>=;RL_^4m>=A3z^QjOFu*0j*VDjb;m(JJqNEhSQA0=Lo8+R9bBz@l4E{6t< z=G_ZbCuA#3xDdPB-Gjv%T{LT}XRAQsmw_gLSC9H7xKrcyH}I8LM z*i?X~Ogl(@^BG{3SYfiS1)YZ`*h0#mrBf3Gdhpe6j{RemYh>StD* aHrf%B?gxE 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 K^-5J6-2VaP*TJg* literal 36697 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 I&MBb@04u7XO8@`> diff --git a/test/test/assets/screenshots/safari-Mac/webvtt-ui-align-end-long.png b/test/test/assets/screenshots/safari-Mac/webvtt-ui-align-end-long.png index f85ad109672f73592e0c750b0bb3073aa40f7db2..3d8fdff8c289517132a2857793a33d2c7cf061ea 100644 GIT binary patch literal 34583 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 HN@xNAAeuf+ diff --git a/test/test/assets/screenshots/safari-Mac/webvtt-ui-align-start-long.png b/test/test/assets/screenshots/safari-Mac/webvtt-ui-align-start-long.png index ce2b4ac05bd282b613a112ff26b72bfbaf51e5ef..0be48821dfd05fa0254eaa3a9b3934c413aec141 100644 GIT binary patch literal 34475 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 AC;$Ke literal 36448 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 HB{Ts5rm-da literal 37889 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 c{} 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 diff --git a/test/test/assets/screenshots/safari-Mac/webvtt-ui-italic-long.png b/test/test/assets/screenshots/safari-Mac/webvtt-ui-italic-long.png index fc4d37d7a2172ac8e609f24c72528c450f681b38..eb2b7db54b91b9ef7e43d2ad86e72e460bd71271 100644 GIT binary patch literal 39943 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ⅅqvyUL4SG08i#fhA}kEkWUd>Zh^Q-K+R%8aNhgU* z5E#V?7M6$GCZCGm!3h650jUTu#HO_S_+)M7cXq{(SXDj2N^X|um@WtDKxv(Nt~g*0 z##TQDOG=sB5-UW}=C@?~kFWLWlv@bXbUtBz7VMfjRcUo?lH#KZXS5a{>uX4-6mrZ- zy9xdTL4mM|Xm3Ta0&8n3lhHNSV$*=ipLSrC1R)(Mdxu(vme!=8{GV0X6P*$Ms z+7bIlysqfEe$>1&Cl40z}sZViJmk{^hWO>Pvz~+myaaW?^8$5#}Q3P>Hhe?oa9Dx#CDVZWIwY^1G_jG- zq`(lXiY#0ngd6ir+InSHSe!IMUJ{s`7>uyiQyqmOB&c1o4kIkihVlcEkR*tO zsd42mtJT{yHt4=e_ej5`KL{Ho2+2~(p-T=3LRwYW{^>In18KV}Bw;ZGK}aG%l!_7z ztecdwzj+{$G1(p6K+d=K2>6{=4Jxj&VoWTpnNHO+z|Z(8vz6J#K=Ru0Dr_|{|MlvZ zM>Hb<0|&RacGXC+@%(F(tZ6(?2PH$3NU;sfZ8HZ2Jbqn6>?5p!{(6OQXK?FO9@z5R zDx@%Zuv-!}kwRHSiYQO8>qG$EC%|K8rVgwx|K`7b6$DD`S2szyqhpg&eqf_-Ge1#J zW`1N3#z1>avp#8k0!?CmjDLT`O$bqmdnE2eD&PYbnS(rSNFxR&#eToEcsiy>f`89R z5J0d4-$t#fnEewZYq6n1U<7vqM5BAai1bweiMj7n`nFtS1wIerM*=NLU69b7&HvtJ z%bN949Tyf%c7^NE)f7Ji+_eW9jcd(X&yd%aoB~(Cy zvfr-?zJF5t#B&>%C_6XE9y#%7KP}NMSLI#-dX+j zC+WTu+&US?vL_%UM~UhjS$!-=r$xN^_9drg+5T7c%L?~TOc?Z%+s#l#Y2t3&K3G5~ zsw)vY$sTKt2|1joJ`QY@H{g-tvKOElpHhy;&~v z;of8aGpfGZ1Cvz)T6OGorJ>2#f}quO0ksFyq_W|szj7o)K5K zy7@vl)!j%}HvG!tNYVFlx$u~lO>S%00K;Q9S1u_5LzCBc@{PV*I}^a0(_Qgljo)7U zW4dW8d?j^BVC~C8@qhyFi4bd&{X6d5h60KpK=)i&91=d<7+Riaqyz{-I=CHJJ`>PV z_qNE~_6?1oV(D|rghoehwSAQ_+cFQtg|#30UgB9wxyUjah`5-H_>0*rml5j+EZ<*} z-?1VC^Q%>i^Lon3uc9ck(Dr0`73i_+Uf#OH+WR%T93wh=Uy0U+Pe=n4<3`KxC zDC>*4zmb1t- zKoXYZ2rWdxge)kMSz9s&^wOWS420rmoO{Ku(CFcqQ`)Xjaz>;XbY@<;-lleIry8Hm~e6x=?N2aSe;XHY!=Q8~s8P8s7B z;}sZ#3_)E+&i^V5aaBhmD<^xr|NAhD#^Ga{jPjAP20{j*;15kh3}t zD6A+{;~|--%t#{OKVM<0V0i068!ELh`l?5K<0i#+WWRCUtuA({mJyAmN z%iizG$H&(_={UOexvR27pK&eY7^ZZgX(%|AnTl4-x6(8vm}mB1?@EYINT+XQrOjvL z*UgerF~OQEsA}Ij{i+r7Qcj6&hJTd*sI4r5-YTUhm{Z5&UR>mCTczzwTAX$PhBP9U zj%mNawZpE`ac|x6&X*P@Mfh?R7mG!>oXPU{0BbR;j1mTGOf2rAsFsdFfAYz*_;>__ zO=*7|Uv)z0t20DwFly0atx!zjeTr`kPni+3TVuNFyr9;*Hz*|7e^dQC4~$PQh9=)k zA?SrdKolx5F-db_@d>{GS-sAi{`SDzHp>75^isLv3)`{h=~}(f_{6jdjRHkh(hRk9 z(H(dCF__rtnSYXy1dN3RG4U}$1=d90h@Ahf^YW;c?IOQ2R;$r>?Qb4sqX;ckji*7V;^A4NaFNS>6(wto z&-K??N=E^lFGAf6=J1K}l^m@xSSr=CC{$qrZLwr-qDsGFW5%CwbBCyjH4?1i(u;D3 z@YQ!`N$D5M>M}E~V7fUL++p{sr?(kRz_?IUuolg8EvGYB^JmI9vG^ZUMkC_41t>8% z3CqaQ3e{)|4W^?2Mj+;0lDg7+d{zu*S*D(^;}yhG!*otqPW>bOVEXpaF_-kZ1dO1N z&tKCM0}IQ+L3C~8s|Bh~lxiF49TTGhsU5F>UoVanx&NE{guxi_qt-DMHk zFx8{Ap6VoDiAm*#LRZVFwUM0o)z9xNv^4Y)KgvVx$U9vLOSbN$I(Mdu*abR!exDa7 zpO05kiTPsZbBxk4aHh{S=&Eg61Wubg{7iIg)Q@O7!2GS2i6#>wqSQ)HKImsb!#-WI z`WdzI*h}o6V^D5z{rkJA&~SZGeR(TAdbxW-1J5<=q4Qais55S+&n>Eb(<3vEYxQW> z_Eag0{h)6o)3V=CIQJ0KFF#ttG~tkLBd*PJyycFUV&py($G7)XVy;BqVF<9#1g~mb zE=!cZy1!~6Ie0Q9s8^on=44Ez-`=mq;&Fd3=xKl4IQe!e2P2ZDP|Sax zxMMR@V4~HXB9ISl4cDpMZQ@f#>LWz2#!glVgF=H_$vUp1dU~l1RVH}ihxxNt_^m z>;UL%#bABjAW|B?jM4sy~xk7dMoJHvJ) zRlBt4ah+UGCFG6RYoa>1UNcxHC3ad&7t}}xPU}!eXc15_u@$kYv>Y&(G zHQ&CQuZc@ZBPq|>rQ(orbjYS~F5|oHVlsZZxUMT%TpH0q%EQ+7)o$9AUl%;v+BX754`v6FfZ4og|KPFBQQ*R_&nO^Vs#mv_9h)k ze9i<8n=f%A#ksGT`q}yi{oH7LC(QoLy;%_4pdkwTqE(XLkd;hX36EI=%$Wd=pMG6Z)YwOPFwIeH?vFeU=UpP!|E2k7V6a3 z_xi)g9Nn6c7nA@P?LSYy^l&4#WOYZBc@j8!#YuMeS<~h3OmgTEtVREVIK_@mOq@9? zSrRxv(ceEH#fD1quQuJ&Bk#7qjEX}N$VJr?g0;-hhu;;bE+#uw;ED`+Tg3L_aS|({ zejU?of4)0*o`SR_(B}fA7Ww7oTW_&DK}C`n8J-@@J3ig75yN!i(b zsg+n3H7QW7koJZ&H=dha`iptr{t-N*8ciKg&{uwK#<=z%#&QvYqC2#a1w&vHoLx0!Tz5DkpoVQgLU8AQ;s!I8`#R6%4VscY+I90oo z8Nfjg-utEA8D|ID`VjR1y{sIqztHVDJyK~58jgo9UtW70n~1m{c2t{|X6yBq zL^SwfUpH0&9)*iqbV4BiIsW^V*Te}@fpUs2tP_Wx@igg;P9tYtJnYRbD!Y9F^`%aR zn;HqfbcSP@UiMK5#faKBQ5R11+iDdU-`t(;FNH_6?3kUYS}uRR-xKpjsOnYrvHwO# zfAkL!QPTYI(lGOpnE|L^yaRmQ58~qOg=Vb8$hvsn<_R((C)Qqf>K>X^Fy2ZjP!m)I!{zR-xl)xcBYCgd`MJ~?_!)i`EhR`jf>m7-^&OAX6t9ue|BdA(Tvsm z`YvhYAic4uq-do(antekTx+JnnX>q8N!NkXNyy9Iqq{Rpw&JH-`-w|IbU+#ENwd9( z@U<}2vNKs4e<4v4oRqS6W}p-(HghGM{B{zs8!&lXxtFaDv*(8o?5D;~qQvGG%<0m3Pr`$qE_x%Cc!0{u~0BchU0BWbyMnuy&RIwpAMZ!dm>c_&#X-(UVj-asf8i8TJJ_Retyi9ciO z=DSdZTRMUT!KD=)%z8j^6iLg%`koMx<^jljLyihjD`(4?u*_3{bYCSfg{^= zFjai*G`4luJs0_rJViJ@sE%Y0_2yEA;TcD)R()ZTz#6#4*AD|s{j8yEC6)F|R0K2N zjP?8Le=zkM%pF~$XA%R2`-xVro<4=Uwg}+P&OJoAe_pu=gBOD@p6sSp{~N5_ zE#ry1xjBvLik8yC^0Sf+F3Fm zv`!!J{~Q6i`U{?Gw%X&XEg^^9T2pP^)B3{-SQ5s!2m29Zp1glhiJ^N*HF491+I`>g z8FWrANRd;Dwi5}6^VI3n?T8&4-E=w0&5gkN59>mkt<8u=yQaX_na4h`p|1s(Ps7Eg zZ8$Thi5{RC>#le{03<=X{JBIO1!K(h&%yIrw;~Uf zS_y@4!cmz6S0+E^-DvAO3cLkJiGgX3t#K@_{4d~Jn&pv6y@LV;6U&x4>tj9ME3ARl zCjU;@Oqn@~vXY3)o{GzB{zIP&@rGGOH~w?uqW!VqTYm9f>02EVFl=M+a1 z4IWvHk+!6yiVJ^l6js1u`(Vby3skw!O=ZTowQ34(wTRPmv!2gp} zF=ML?bnQ5lS>G~$VE-sdn${UWe~(V+aMTCxFzNix^(*+3$Mw+lKkTO}VarS>#+eRx zhq;T1eDk5akOpd$>w{ki0CNW-BkqiifQDpRyC`kzK-%=CrfWmQ=-X@|11Ti9aZ$=g zhWgu^Z_u;-v5>w{#R73(TBFuh=o5eWlq+v>fL0gM@8coL=EpZina99%( z;9Q1{A%+kpap!shJZ|gXfFy`uRQv5qPdQv>%XX6XJ9$8=2c;Sj_ZOW~HISj!KAQ8gcc??M zhKLdcuB_LZz_W-NhSWYSyPRO2u(I}{LjNO`<|21BH2s54(QxUFja&cOOaAw~B>Xk5 zAo>5H>8qon+TOnz7>1#T?khu?;oyp^$v$K=j?c%Pi<^o{D|(28o~X~0oZUt?6o%(QOD5!FPkp zf8_Q62Y>?VMMghrE6)D@mWloELM+v?$m zhwv|&8bdBQv{HVgfvKUOddbQdPDxYg;p!>#AfWkp6 zL?SAxiso$RXIjF%FhF2QXA7S-nSm85F<%@e+-)oSM(yS9XP`l;_5AIVPM!~=8T+pO z^UP&pD_*6}wvX`RUpKM{v{r~7(Xyu~_Ph7*%hl)rNx$aa0>{B&UjD^-G1ci5puET* zl}e)2|3`KG1eces&@S_BJAa6lP4 zM8RdJFDvoFnp)o)?EXle3t>Dh$i4?!=WeE-o*&MSrQ~CY)*YkSyY}UaOxA1ofHHV6 zf@_e(OM|p^>YdZa5|<`vC_q+7boHNU$hk3DG8I|Ks=A9_EIxVz+Ov((Yz*K@qHKjp zp@iU$DL{7jlkG9HwLBK{69W)r>-mmS60g*k;StMzKNfyZIt0`{XL)P*#olavcvO^e z@%#X2&NY5m{{v)Rp+lhtP8<##cqKWi3?u~)Ly(QRKaK}{%!_Z>DaAJtsM*<=bm9>q zhsj4N9EU-96y~`qTH5!MthC`(%Zufy3oWCnyQ5+{UVDZmuCn5Fk}h zj@Iq0pKn=)l5|b=@rjWnrk<~6!d`GBJux!H2UKCs6CC-KT*A)525xqp_LPRVL6m+g zHekbf6wpHpQeu8%NdUPh&I4uRNb_h_Qjjn9z2NQk!X72{~>Eu8{5-Sh;)&sNC;{-%psJry zd*>$PUwg0eoys;S3(`}1^{5*6H{Q?u_al{2_5g%L(zSZ;y`DJa;E=)c>_!Tb*};!Y zf>&GnJ$4&I*4Nkyj`nAkh+XIWGEt5C&+1O=wttjyg->HKl_|o*9CBzy-IL3>x(3A8 zN>nNinvvmiA(v<$rXmaz%*z~g9gj~;s+TXWDMen=Hkk$BUM#v3N}M08&t;lh4BMF( zM(^N_&?1)(hw8Yi=tA&Y%S%YNa+FOKq$+<@+wP7#70Nl8;hD+NIZyBwPGGoI<_S|otZt$X?JW!+~RqGSYxj-EVo?q`=? z^Nlc3{6Kc#G}i3cH>2;oW_sxOkdv3U{9PehpJj!@%K-0##o>efwrhgDHg5!LvDB6#+a1z)KVQ5p6u6;aR~A+REpeM^Yv`W1o#8 z1{h`Hzc$&>^wg+9{|JOAtu`-hAY>C?Jn5Ihbj>{Ne=|=>=*gAs<5lUK*Mg;Q+y$=d z&SgJFo&BAwb+Po_@Ov)hk6va|#%*}^kgr1`>E$9Ub?LQSDB?N4uP8*u z`FXS+&RBU`N`{=J8_^u57$Y0gB$21{OiJn$v2(~4@1tuw*FzqCzmwacmX)`;DdpJ2 z0E|kIJ(|kpJ3X*t051h0kA|K!6Fz3!xBG{2_uuQ5J;K>n-ank5$Ion*#lj-lB30S2 z2?#c_sp{e0Fps-5!sS!{ZWKr?VJhq_g6JCy`BP^LdJq^i8noZu=32;mX+2iQ;idJ5 zl*nCx~eTg+T?b<@W8{#_N6;Y??ORaiWuj4M;m z%m_w321FZu^n3m8S=`r`CK)`p8U6Ibuc@SSh8VKPN3rZ`uDj_wC64i_I z8Rc>EV1~=+>*AJFF(|#<{qJqgHJ%@byIXX0&GPRVN&#Qd3n_twXTJh5&1<7W-%lUf z9E^(5O1nXKEG-H&Q`3x3e%Dn$;N?b_uuyY_`}^!h&g}m79alp^ijE7|*jR~m4WGk_ z5#sPdy_6}DH>c6hyUX`;=UTnEnnS4{@JNKGr(S0HRyD8VM4+-B9~%AlMokvPOnB$! z`?<7_j_{55Ei&h!m61w!5k~jPDFjK)Vgh5mocb_eqU6xz*Q)i1wM1%$FxTE!+Vq@O z*I4}GIvZAfF%_W(T8e#c-*cPKhyP+hJVUGJo_z2V>5^)OzV~Sy*zQ>2h^+G1bU>=^ z9wTvIzI5c|l+yB@=a0gp`I?{Rvf1{1g6^#gX^~6Z=#V>RURZa(cd&WYi-T$ht`k>OLf2rDL4hszqg+VqFz^?me zHHHxM+*yh_M3rW%Xe!W%NMwZME(D=7Wj9;cw&~~ zlta@2c!pO-O7qznt;~L=illZ@;N#p8Mk`8AEefADu4vwOExhUSysT5E`3HT-=KqDjv zM->*9#sD43ID=#!4aY)vyNDTJ3_BRf;63JSg|)TxIxjE)>XPL;U@#hZOr@?KCo2n- zr#ZY?f4)r9O8UnD<}Pt=856t8T7>Rr<0fiS;eYK%a|k;@bT}w_?l~QHyq(P0=@r1~ z@Z57c?Dm5VuA;OH0$0KZZGY&Wf9hkR#39@exEsj4`g`pH2mcQW0J(zDj_7l%{Npg_ zSDxM%%vtXHJiv5(yuV|U^;)oJzdqPKPC&14WI2dWKYOf1(n%c%N*!I z<|vq;0R($JACAI`{So$na3`gZ8>#r(m3 zMDwCzlnSE|V7p`?jg5_lWx+dfmG4KYdi71BxxPd;eTH!3zS1=ZmDLkSO3D+>Tz5W! zCzF!5qif4pdlr=9+R+$gq<`@L{Qn>PR9xGd2>P~Pt^P-{_Eu1^RDntpbgVG%ZZ3!K zRro&Ioe9WQbatJN?3@MlnlO4B*OAiP6!nzG$MI;3HmDK}pLD%fvpJYZ84{rvY6~kx zc-jmxONSi06}Dj?T1UO0m1z#XX$)-gr@F2`m*-dIeDCs31>UoT zt8)LH%cV}xn!8=D-hX&s>@)Lr!DIJ7Grvs(_j8+Y(`5p0x1sgdO`M<9q`_8L1&Zw+CFFK%Iup~xD!L!ZP0K~!6bHU^bZl8oeL`BmyAg@$k!;35Dc+@yQ9r5S zWGb}@EX}ulSeL8w)isjA{9thC5w98}$fyP`P1yCG8sm6Fyy8Z2u}G-shlk9A?l%_nigyealhDeGkT&Ve{tOvMy&z`d=sjKdT<7#p(__6=sW^+)ZHkl#0Lz ziN1F1YWHwclM~1$J49MZje-6!eU}qrQGnhgA?- zUF975T`wvvLn8=!R}IgxOVc$eJ;-uJTv(ePQ25m3Hgx_2#f?E=y*pi;rXvNipQuu}Nr>Q*OL%a z3D!N%*<==iTRm=~8osEY_aE+H0-cVPJoCkbZ)lDnnFYxgplNG zq@8bZR~3YSW+BMP)n2MU#2mOfJNTJa@|TF%xM6u}L|I_%c1TR$Y%r_@3m)@2*2exX z0_;<>4KHw^9=y24%*<3d(h;ju#NMx#All%!J{pMErh{M%!^8l${1It1xeKzZKwcmxp@ zc5+SSF>H@6{Ax`8AvQXo6mmjA3?OqEW)XFW|CP>y(6O>JWe6SaFQYG29c{Diyzx3+ zS9u^NrFK1^r%CgAvZ0AQ>U7dR=x@LU;IH#xTe)rBFM}935lq?*Dsnl|nm7&z# zkWHuuvJ6{c@<){sq5ev~hLn(LTWM7<1G3r2?=rvrm>~i4sba_GIJ3^DyWe?GJ zX~~_jUZq$cIC7Sh_ zXa49H$DyFhie%v91dDK9QWE1Z}WV~@T=v%|?HqwqXa5q7pc zl(MEW%=HCB0_ey9vOsA%GZ$blvq8nzZ=ctP$@T2x@`$Cm!1)Q6!~AES+|SO%K`$R> z2MPLJulcm>ch1**xIx&2LWKZ+-Mx+1yZh(lB==OzV^yf%Ary_`qgi7dp!0ezC)W&X zt=TGrpDSrQ3Va8@noXSv=*42XMsaJYyS`!u_#Cc;PsmtL%{m(1 zuIT-E^<3kXr%?Dcq19c=ztO-0&UQQMZUUFU<``+IzbE}cfB~prsL&}We|BNUI>2@W z>~=+^P^dk%kTDo_#78fF7?blpN8`QK#A+*TZBA{H_K%kPhxKUx{Caz?gaQ*26S%p; zpJMY|`3_fDsMQo|snevUrOvh7I8v+cFh0d#1ywcoouwE+OJ2MDy3272_?$A!9Gi7y zj~)?v@>Lz3*viCp@(5S#jYk|y8)0bpMmjnsP&Iq*E+l;Xl>2V{Q>bAAJB*Z!;`prH zXw-k*L6~R0pJORd+1DPJMa!P(KK~MtTeZ=j_yX07rjKMhz6yfwNi-B}-knJ*V(a3J zq-K>Dgg*OaCaZK#6*DcT{_*L_DKN~ko`jxSdH#nJ2-4yw)pl~|k%QoJIY zw+y9kR$0#Je?>QNBhWQt^>J5gvFL4PZlxsoPnk56C_M2amS?b!l z%ZG5I2=s_ZsWqQ#awm=Fj31{B^&l99j=28X;T2YOz7>%%R`haXD*CK>LeWvXMvygNer-(S?$ z@lg*2gIjAUG*5if75>tr(y+^gr4^<6TBlU2Qh0r1^JKPOhdmv)cE({9@omGP*4c-=wVa5GUJc-Cm;a>A0xrCq+c#}b&No6$QDt@% zLRy>QeB@~X53!J*!Ea1;)6A8A{2JSmU-php{@IEjWqY);$>2U6)Rf$D3T;63z$ysx zEe>mg8e%jU-z%YGyYYy6UZUN%SWO!pu{wT?U(le2I6l^Jfyr9#z>CM{&a;?L#6f9Y z!-b>0UiYt?fS4rJo`^YTfG-ljP@p`# zA|E3n>z;w$)+d+y)Cu$nB6E%2SP@i(veRD7%*KSquv zy5_}&HUdawwWxJpO|b&CZjQZdBQ}003H&<{3U0}!sHO2U&W0+Jd=TX_4%Na+!hVxS zhQ9?1d4r~j`;}CSITUE2k!VdYJJ#yU{303k4CV42z1%3DXBR?3E zN*?#$g)ZhXc*iz!*~MzC79z68xYH5t<8f#&AtbKoMdDCLegWe4xO+@;9!+FyfGUq= ze3=#}Mo=_*EL0TOzghctKya$QY%)YHkBv<`GdCt#_t7KR@mT}asQC{(iP$eW5htBjX*J*y?}@`wVoM2*!H+djqyt;V|ShG!sPQ z?GTz)&wVS738g`df*+})LSU(4XGDmG7jTaM7U~{0N;TgS??1*>@`!@CfnQ;a-~~Tg zOnQfdcRMKrl&5#8dZ2(8b)v?=!dt(Q+pN8;)bTyrR*_TZ_q?4UMt=nx6MFEo!mC(i z^WfEdM?L^7!tqf+RC&v8ij^Ni-?to+=X^w1v|D)EgbhUQca%)s{FiOm_^+t%{>uT6 zNhS|rA$a-B`lwn~9fb+>ZLwpvFU~9Z9ytwSFtSks73-ZoYroPUuo~$Ewy%?nr)P%U z>wXUvICEy9s!ARp2CoamN2?I`Q^hUi=rIZbRQuiVCo~xZWETH+iM5BX2&V?a8Il8v zwzj2zCb~GZ=uy$31z?Ldm2Jl-z0-x=;Y6UZKDHr4u**&Zm&j6C7!#v95)^*H7i}S2 z@}Vj{90rW`+MMty3w69p(mPey-6Np> z?7#@Ut1HFCK?#8fV__iH2UniHT$D*h3j|VL8la^;ZVO=t!hC+bTlNw3By>7g>Km7m z|mLrx(ZSF|s`v2+<02AfhFXbDovu)Qt;~P)DX0 zl8!yV)I;jsBpp3iB_^hn45a*|uisNC%Ncy314=q<`DGk@3{E-Dod10cNNh`4zx=j3 zI$myL0kf_=$Jhmfq{&!~grQ$@XL;2S5|#?p4}dr0-Fr&qY?mqX@;56ov@a z-dAI3g{Cut+Nw|%BJWC&q*VFs^Mc37e}U36S4vk8fKusJ>OnFH9?`-8(IW_S-9lEd zksw0RBbE<~Nz+XhLhgdvMegW8Vv}RWNA%45w-Unt-W7@|a8f*S)o1f!wle@LIEf+x z4O|N)qzf)Z8VaL*2lHSkHUQ}Mg!X`8p-J}Wk2~@E1;_L{&RC&8m9-9^$9|O@Z+7_q#>0^77g5fNZY zb6%IxxL;+uXM>3=?0?Af-*!~;FTp=~7yt5(UY&2O9{jmJaIaoEJ-W73<7ZRFM(Rft zVuF#%_@E~>6v_l90%s9_IQvjs@WwDj!8)q8&qDoOWHm+b@SkbBV}M6JIrqSxg~EFr zgw%|*FhM(O*<*LO^2r5Fp(55HjI#%br{Q1@k#P1jbf;UW=@JWphsCFcEr%O{j+sTC zMa+$zgI+YLsSY;|MK8Pm2-qxzQiwHiHL)|GMPTW(GSYqjWj}9dCvs$at_%xTIv{DV z&L744tvl#qaY+9{ss{w^&0Vg+Tp<}yHaR!~X{#rXLT8hk7S$?YtyCarG7Z7y7|}kt zF*h#+;aq#vTBXntWFb@oof!BH?Ah6}$RB{IW+SJIWP@Pm3_6rTr_n+EE%zV?$^&jV zAw-QcnOGCM9LfoBU({$_H_&%$l>mc|F(cdk3jzOSgaCIgi!49Z;RJkc1{9?1vx9(o z3-$YN111|(AF0a-?X(D8yuLU&F4mc?b>^a6_KZF~`=@iXynj)@bzLpmdd)8i`~eyB zRb7#@Ta*WZ%e>S(yK?Hu#L2*NkeLpi&;K4`GR_{gr+3%@mCaEBrdGtFvieKv16Pp@ z8@*@dDt>C%l;T?H%pj0qqU#FX+!SNhOE>P@YrMc<1_K+Les)%3I;zNW2LSfz8$BTa zDr+!hKqfu7YS~js;cKNPznxhY^}GDZtv#!3d&k%Hw|SJiK4a%-J5V z60cr*&ov4C_q|YTpS8Sv`PC*fo4}h6taBow19owy9Ag(2bztPR)w5KT07T~Ino>b% zy2T8WeOPF7DJyVv6QKjClr||vm`zv}1R3(xjycbJmBcDGF;1EB-TTU-kL`HexSsju zHk^Co{2=<3lZS7h4oH+zUE5gTFpQh$&m*=^!-~Q&&ujRJjoEY!Oe1ZKO4%!l(@RS~ zl6FmCm17ErN363Jvy|}j#FKF7AdY-xx0*|eV?0|ag)QJwV}l>?E1&2Qr%;9!(I{3Z z>nA@8wJ`!VYvMFojcx~^BUfVFs;Fzlu~9=ovvAr3U$39BN=oyQz4={83TzU=UtDrk zoO5Y`0F^F|@D|VVe(NlB>>uPHrXkT#1-P--V*^I83nt_AIde!0(-$nMXc=G%xE+K1 zx*`YhvfpLjo<2q18#AzT3LRO?O98$XsTWtA#&P7=(eQGSx_U;#K#7eKX>Mc0NCsXI zvDKQJm?>b%boI=le*XzG#d`1B!lD`zU-6+l2M`S?%m#s9lHP}x}-MJNsp zlF*REBalG3xAX8rcU3r|p^!AEoP>@5NIaS)8DvneUT%6M8e6($s#G42U3Mk zrdPuA7JQKDNTJ@oMUb%p^lJ%?jbL-HxObK0YFk-7Bszc#F}nw=0T^w=)lUgHAv}S5n$enl7(8K*QJG<5x0x`hCi!c9fCV z2YT3kNuEuWZQnYsCAi_f`$xp%cl!3a^=6IDj5js)4&;761m1((?M%(JpCeTppXZt$ z`On%1LS(QA?jp$WkZ3pLD?}@=sikwMGR;Sv>Ro=H#PhPSe0q$PNLyN74g)im=K-b{ zxsLQ-)){j*y7&Pd1u} zm<8@(GP4xVc7%x7<`=|#fx`%?ze=4RYz#VX^1s-5jJG2Jx-{cNIte6IgDgp&GAG=a zb%5RN7&EP9<-^=)%LdF=vm+;QU&8%Hk*JJAhxrW%xz@@b=w=G{bG~JGqBqr2h}$&Q z`DT7|;cMw6Nv&r5KdcL)qe~!&b+M2Ex_6a@l@-w9zS-QoO93L+dfPQ>VEIqUOBpRa z-t_4EUf=R!-0Arv%SSm?^>?V?Kn}_0f!o#xo!9i^bbh=7lLCs(ED!9Lh_LS;5Y|Cw z0WY062^_Zl9F^@~Nu(f>6*8niy6$DM_Id2`B~3R%*G1rV;kfbDWbA$oH9gur=`P#gb-oQmob_@|2PnR>n@?pv5mwgu;NBIm)^ zltX)5b^kwH(M@WgdV zqV_uEhnA?Qo;CCTSgN3nZ znyF@iWWs8y6*rq&jE<~7H~5VxuW*3wzL>_-&L9P&QWkD})ZM(YMk)A8s37E@NFcsh zZ+e=^#^U%tktGd~4#PF`vDm=Mk6DP7l=GKG0oy%@BL`MIpcaw zC!LcY;8P2NeBDn^K$LsDeL>npX(jKv#Y!+-#9of`sBhM?gz9Gq|CN&mh`cP{>c=La zzljCH^wY2Ue3Q#g);+l{;S9Mi9i< z3Omh@ru3<7{cNO}kUkUAu1Mpc_r=Q`Q+xg&ZR~OEH<2G6bqx_Gb?&-xu6;_Lib5+@ zuHFZ8N;XDp-^mO>+GG>~rM#R?fLZYM#D5fT6iSr-^T)eb@D$0H@Lc_j6 zjbSR`z0vM5INhaU9(6{i=&6V&!yuzy37|nx4++`s`ZeIv3L4zR!fAr6bWAhF|uvrSWdG*(|*d0tA{*Mrzct&*LZX~M0>)zR3S*&M#Z98* z^|By%3C0x_9v1WTC^Dx<^GE#*^lSE$0^T1N)hlm)EV%yu)7;m`d3y!@G^Gzn1yF}Y zCHMYoOOcCTlVMOu;-{PqKx3ji#r55P|BRD|s|dt5(&q<&2_p#lB%2kx0)=KdTy>@h zMxKtx6XPLKxP$o<<5CiHX3ZFF9k>*)3;MSNN>p1b=n^srBgV6>j(pVJra$IpiTa~A zNqKVUEZu=kxW>_h$!I$p1i3yjHyINPS1C@nT4{=};l|~r{NVyGcUV2W&T?P;&zomS z`^z7nh3*3SptqlmocQtRx^y17FNl(d9Fds^-;rgGX2oq9@-PWHcO=Tl{K0vq{dOEA z1vu)94I`Y$YHc^UN?Lz7w})`Y$}d?(HwynFKk?f@QLDOY|KAJZWR|O@$A6l+7P! zT)T8;MlJ;p_dAdjJtsaH#By<4xja?VP{W{MWZM!SOGhgAv>S;`R;w_SkF}&?@^xsX z+0WKl(Ezm`(__xaaEWsdY7OQ+YPyr3BygzV*}u%u&L9HY*n(uNg6xSPk)@H)xBqWAa|ko-&bny}3Cqs_fNxR zfwvrdHfldvAL&;fA}+@AWY_6RS2+lb0Y|g&yX|0pqkYf1o=T;Exjb=LAF$*Mvg`3J z8(7Jh;U#>u6DlEo1#FcW{N5)mP;GzgY+*Zbm#!oBOwFuO$BCQlZ~d(Po;%||^5%J;C0&QYM{@--0~p$pR5m8C_)5LMT5NC1pg6liZ+_9u z)!O1Jo)A)llFq<@Ea9zk1hIv@VkKp{P7C_9(EG~DK00~``D|}r7XRPppyY1(Lzvb> zh+TVZU0Qa!KXnLC_ZM50P+STN@;y5qYViY`XQv;m?b#kwf_1%=zxj|6M4GsUFiqR) zaQOCOO&W&C-MAdYkz{o#P7ZY1iia*faj1KF-0%}8} z4mbQi;G8BbJ7rN2=v38Kx4fBhEC>D zB3NxG{_W+C$HM7l(8u{Y0wG9_GFV~soZ2t81J3B@lQ0XoyWeauKa_|AuC!92_b&E@ zMYTji+M5QYq@~kLO&B0VcRexsaPZ@~LLG#f+q{iM`-L91kUt$*0N*6|E9lHiX1cL9?Yz)|HYiku-Ss2mgI)1wCf2*7Wa1O4t zFX3LOEegqSGQW|MnKtyfmoD#eTNK{BQRhf0=tbPBZ&MWk!F_txwxfC+MLO7=4Lp7VaZ#ZQ& zU***NoHunXwR=@4!)E2!A0>pZH3O$Y)iY#jw?{O|1ZQq-*%vbxGs5?OHmq%Ai=2$5 z4sc)H1Sr-iUoV_TaGTcC;>kugcvC&+cP0isA?<7vgB3(1Lc;VuQ}$mp0sn8L2K>i0 zqg)>uUC;1Tn(D|Zussxdh%+VY)j7MAeT{_doGiG2YZ_U^+c7#$dCqe_n{P5@9c1%|YFU|YsOV#RYMEo2G5k3rVN6QPf4E--+7LSIh@lRvKy6taNhrSOWG=~lr1DJ65*+ikA zrcHof;!x)r47d`87N=9+RUI97`(23YRJR@@lMF{ebCxJ58ZixsQ$0bU3#4g}lY^zM zPx|9^p43%Srg|mImTIqz(|PXy!t_KCQSZxNd^mBmr^+!lYrs!Ed%NYCBvd=04T8 zcyD-Fm)an<6T2;&rb{#kzkc{CW?Vo7~bt z`^4S-K65O=jBra<3U6zXA$oB{)u3+lLquAp(afhj8 zKiX~uo6+vb@dFUY`Yh2wzz&nN$r&~X%)CF0q@47U2fU`1-SL1H+pnIa_kj_y#U!P6 zrE7Q|b+&89U)42w3faoKkzl|wBVH}GBv_OY76U+?8=zP5W43F{DdEfEW~TlCGMdNr zv3PpP^fdhCa2W|lT7HUB&dLGO&ym0S+Co(IR6iw@I0NoV%S?y<8Gma5PXHi5TM( zGKL#(JrOs>xknT@7n*XDQ!tcK9U4Anf&bXl&q?JZD-3b)zP!wjOiu+l6~t5JUNm4C zc>q3X@t%VC@sS#{$L%dDqA zYvnQ9lQ;0M=I06eipmLoxflsXqtivQQh!xWmT~FaJ46tjBZY1RP z5cFD>fHNma!B&9xDl|Q!rI%{Khfz=cX_Yx9uPmp0ujvZjj$ksl3hkmFqWH0~Zd~$u zx{!0emtcK$dt#x3p1z5~6E`9N+4K($9s|vPI6$uKQhWF!$}Q_9;Lsa@67Y%)j@z8Q ztJTbQ#hzw2*Dj#%Q2U}YIIlZ#B-cj-2j>rkvGFAHH{2mSP3;DL{?4*Rq%-#utrThu z@$SuaWx{kYRP8etGg@24L2R8Y=RGM?+D~=B-fv={Q_U;oCYCSx?_}iWDu3qaucUpB zGH`EfwE~Nr6tH6z?lvq(_iW;^JY-I_am<)T=@O#r@)te}LGM8eAlwTN#U#j|et?Ms z4h~Fm$OfKRtQ+$42OLxHFYn9r%uTa03k!;Jt>)KaGmG7Ae4WF`Btu45eR{5dVH*Qd z6LG)&HzJfGR(K)4tI}rv|7<=G8XzO?OW7+QY1NfZdE{g17?eX#Dm+&?X?*ecDiHLL zP$AiAMtjQ$s@K&11kwdbe@sL|2|8LYSP^)xTU(YWv?54q-bdOzZ4Qy!6?XE#Gy2Ke z$p}E78An7$K6(0t;7{^2U($KY6{yYL_6-q+W9Z_LdTyh#lk?kr?}9E!OgKIDRf zgVRFm-X0h z7+?`mKznnvmdel_N^pe<(nwkzX|y6>5ViT&!ax_EkPo(?=1PQ*EvXTe5$M40*9TYE zICG-RY|TUGj`!eXLB|zuS5zuytiZ9govr?Jz0sAm=$;-(b?NuDDz@@np2X_GSB*)C zV{3Af=rlQ}>v_b`uKRKUU;WH_pK?|bQrroKYpBiOuTaUY9VAN+V0r0h?ts%f%= zdzk3FrBMZ3P&w&?*m=4E7N4=r51i9}XIDeMdsiIxqQQn^XM*RRhlt@7lh6a9j0dtE2 zHP|3$JuLV*G<1*zS?u3>Q1QzAH50O(H@93s!YQZdjkjMn|D@SR1oXmq-m>cQ&#PSJ z)w#YNkw0GkPBZRx|n6JDk0L?U8v6i!TP z96O-QfiY}lGNs>^9d)D^s2z_ zb4^Hx#_6Ugw*9kKP~u{*baD;MH#ongeHRmDR8O227aSJOXtC6T0WMms5k0P`s6s+T zre#~HN#1@&aC#Vs2w{Zd5YXSoDknt`lkgTRTqi~hwZv+^F7mQvWKyaa4#$ro4vtthCXw8;JA3L`MEY;bOO8jB$Cko;!s8Yxgk`h;kGZBr-uT^Bkm3a5}nAvPKoyjY`v-VY1s7=F zgD-iR{N}Da_h%zPn^5PnB<+f>7sg~?kej3z2ONY%dL|})$HgzKZLA*!qWA&r6yvTk z+4+pa)?6%i>&pZ0yc^Gb@vTw*!2CaYB+!1`V?z7WA8i2vhaLG#ft4bA>zzG) z;F(+ulv~Z(npEMM@O}%hoi=twBL*|fz0Uo}w_P;IoA$sJfqE$R=F67{peV-0K~O&c z5&$dJF1dT7pl#pF8V~A4+k5at9$BuWr%WusdE78EVt3H!K@~DCxH>lQNViIFS5svzWxzddx=YmQ))fiy&_7d zo$<*ys*D?mW{3f#57426d65^{a<1LGhaK8x+Pt_+fAd6S{At?82H&lefXD7O_h%Zs zG&)M;cbO{dtDnDL(+Ff-n45KjJebJ&eOr)q4#3@7+i7v3A~)*k-ZwsCG2VA79K!?55^KWy+*Xz^2z)ol6}A>25OG>lv6T z@l&qH4Nuo3gAD_V)PQziW>ystA&cVPHn((yM_UDNEe58_Ea0f3;$n225-ihczpGEr zF8zj{sD8UND32s^DtR_T|DX(%{xm|}n7cnd*&L_3h`F4#1fEP*1YYewYnT|@OvTQu zaXuAiHy4bo3*wLqZ_j%UBm-CWcO1StLbAnZ1+0$*Gj64>0YEcX8-Qi6>s5>#(CD&R zPfn2xx+C%A-HJ$0wfq;Ay2MM7G}HIlbY4^mg*4SQ_-`=UJa80HIljk}n+{;cjjXKS zxNWX^x3t*)!t3brp#Y<$*)kFEN7U0p!t3G9isU34{Uc zowA|HKGJ^Cbr>8>YSE!en$|)rFap4sz1GSV4hv@od(P^V)lX|1k0pJ=qwlNLMvcK_ zeOLr6)}U!#h5`+G%8E0nY!r?Bs8qb^k@gAX5#4o~1Pn6rAWows`fcAeL*SR=wV|!a zGAyG{g4h7e4QFJ87K)|;Nf-tsDLPUnQ0b{ZdyCUgfkK^-Dg7zK%YEjmtN=2si#-hd z`vZ%?5ca$7^O*%)2U!E9*cok|V7=dQLZ(>Y9=|%L_LJu#|HQq)KwQ)zN8rJ_%WGeJ z7v3532cNnJVV&xJ*4PXQ^S19;J>@YafEDf*s{Jy*BpSw6Ti@IeteHT2WL$QCTHJVB zAoK3CPd&sy%gb}gX4>jyXHftNJpaA<(XcDkf)P#poA3`31`-WhW%3p$cfY%O!UtT^ z*ik^@GRoC*R2=WxwkUZwL-9by2uIlPtS>VnS|xeDoDKuD?h4KUfTQbcY zob+CNpQV`j-}jmBsK)iD@5&|m%X%Uuc`9Hwepa4QXF$N zE+p@V--G5MwkHUdN?P#6d?_e_v%cK@;}O3i;7q_gU0q!r9)1}Qv~7!ZhwnapWJjF6 zz^zZqO;g!z__4Rp5&voAbEpYcb+N%bUb)uWuQN-08^mJqlZm#*v*1r&mpjpmr82@_T(9{FqrMlw+Cifc)B0)gP98qYR>+N~?Ey4a7DFg4{ zELr{-3CTQ;yE9U<-@g&%lR!(ExwqI9U7SjCw*4y?VB^U%!uOHtkDLzP++1$^B$tM3 zJ<)rj?dL~zwSS_jrCs*I46<}{iC^9R$L?p7<3u#BjO9p_7UKQd`;RZSqsaP|hEmfO zGm8F2Cujf4v8jCKdWAo2^tXwD=@%Nb>#JTr8{1Tq3WHhD^~6V$cIsmMWa5CV@Wd<3 zd-t=~5Wb-?!jn!@El`hGpD(NT!ym`Xv#}&5c`VWlJ^LKSHZNhnxt74LRjfoZx=mzl znk@XS-ygA^oey#|Xi8RAIGg!`ZzJO=j{AI;!Zj)|fky8E4<9(+J|}O_yR@SGek}A3 z#AgLvEPK7ZJEZoarJ$ zVI(B^hUkdGc1GTC_+GV z?XnR1QLZk&Xs9X>?Xs)OMFIxcSF;8Z1p;A_u>W!pXjW)#awH?jmr5~G18RkXxcH$o zuG>JRsuzi^jau-w_Cv#y#gYuAiDtMm#gHsNLBSOPen?uOin~L)Ws&4X{NN7~N*jvhiarTb)yB@z#h8^# zs(tYWDvOpPn+1sr8MBk;S%!iklLz#NCEd_fAo?Cdvi}DWPqq(TCmlg5V+w;%-3cT= z{!2D!s3C}`<+hjqzmm>9p2_$B<2HvahRykG4zZP-L(bEvEvFRXgHTR|9Lw3v`BXwV zXNXD;MN}$s7)f)ikW-Gyp`6O0;dkx(^Vc4G%ynOTU-#bkb-(ZD`}N{?W}e~9plkP# z*;skR2#R!hT?(@zMWCM)BnXv08HH@kl>oUY7f8sT#-{x{ABFZ`& zayNz22U7vWbM0X8S*C{_>?~*}nAA=VpR*=9dFTiP!18i&pzHyNOIhRVQVu0bq!a8xq(m|@Ny8i<61Xfd z9zB*uVlgCE88Yz%0kksZ&^{O9QYgI(b4=8VDx#5O86T-R9S5*af}gN@^1zO@26LvC z@kZZIZ9K$kW;=utMo%6#3~S0EitRA3BBsK>lL4dOC}rq5k1etto-iW0tR3PRj5ZJ> z=Gfa>iLLPR9(~Rl9S@T}3264QprXS}Bt?{d%n?>hFm+Ji?JVr-@aN4{-f& zsyt(EYHf+H*qjo`#>;i6xUTtCI7Xae{)ceh&39vLe%EEX&Y!ny<-FDF_One=iZH8* zf-=Sh6Iw6u0z$}#%W+I4fhL}emj#I4y<#c;!(pKBPf$q~(+`W=hjEj>3ql{x+$w=+ zBRu=Who?+H_Y}A8F7nRdPr}+UKT$M)izruY{tVIgRiGlMNVt8Q>&esG4~x*3yz%Z( zgIiy%xa>b}9GT6EDW(2E5R|mm4R9G(F}>RL4*`s=0ZExM$M!QtBcX=5Ozj|*iVn(t znwQg7P05^*er%1bjxC9u**?Qm0oXYB`)XV)3vUvO*iFmAKP?2TpQo}4JGt;Yn@3S- zus~XRoCX*C*g-9pl^qFXX;Fg~XJ=oM=%2+6L8ynIh7ImHks=hWOLTE+oif2Sb}y+m3%>i|)YjRIV(S4^g7 zJ~-#`*k0}Bs`{wov0#wQ%nQKx34os@D*#nbnPT&gw6@%{io+Y5@Cp_i7JMBo)CvXm zj9kvFu?*19SWQZ+EW0!hSs47)uH^>X;aw|u`N*4Vf}pM%=k{v--&-_GOP&>)#R#5l zMFNg@tu4m=(nn7ews?=hs2aK zfgq6U!5p`{zZ+Pkq&;{?ajkAph?xS%@4mpd?ESqu6Ve;tnQ<2FN#Kju!x-Ts-rSyV;dy`_vDVmyQ7k z0sdq%}&>$UFs-~|Vr-y-^ZYs?IOF`EZyrh}0#wv%%vUH{}9 z@Ba89j>32}!pG<}0Idliw17zi5PxZ&6-5>Uj+kx9sieQB`?T2sH%wOS#{gjxuy9jK zvB1wUVM`SM;bX&7ORGUV7F4ibj`@#>Q}|+>k-!&>h$%cO!L}ZzN8yVW6j;D-ACqWWjWW`w(`DL<6m^><%lUwa zcX@wMk@CcQ&t*ngK=0o+5|KaBzQU5tQtm0u0%Smx&j`WcEKmRrfx@m<+kr*+8q~o$ zQr?gLPv^(@csMhGmAaxZXq@6?7D6iA`jgTllCHWgFo`qPhb| z8mVM?3H+!ACcbO7{IQ>qrg=fP(yzikAn``95XZM4ynFEy)>7Jl65rVUDx=#~yar|FCE?FL>3I&0~ITqILg&5&7n` z&{xp6@}IA31U1BH6=%g(VRhcV`>XgEoRv=T>cA@us;SzoZL*H5cqpC@Oh9_y@W4;| zeS_+AX-3}RPj>Yb5f;w-lp6qiW;fBAX2oU!EmyhJCD1}^u~Q5A*K2@TrUZ~0^QWvc zxywRb3RVgo1SYnXW!O`})8uiDe>Z>aj_M}N^YeIfXBs>tW$-UJ&*G}i3Y9`nNxbS{ z5>0F$FcT_##AoZ2M_hW(_tiTjXLIJ=xsff!~EysDWaqpnLOsvI~~&{xUsT%PKy22cZ1=`Pdgj_7w=iu z`Ob#fR8?J}_5`nd+dpY1oR^m8V6x>6e@iNfg*#>&akpokD|S5?4-Z|+>09g1;*ObO zAntCO*Be)9?-U(=v_in8^RuvSQ;^CziI6lM!EsubWE4Klmf7*qIg8jol2vZ| z9~-O?sw>UE_weMCg)=`Ra8!Y&ExzMr7;C^&4|} zf;od>blEXYU$- z?icsDbe*~U{-|LgB%kXNBO+&Jb;}>viOU*n_ZXuLqGX*bc7@ zXA)PBjbeM9!ZDM3R~FfX+R9&d&s}w|cN-G`ip#Q#-&Mi+fLAcFy%+G?fHtdn{Qml) zS}G2ER`oq|ZB5v{v$95`A5>>1oSymgyBN8hsBn7@80#eFnc#kPMH7qLWqzKJ@aC~t zulx*_+zb_kg086NNlLd?od<^Q`0vdf*^2W0#?=r2Oq{esb)8%hJF7ZRpDCnn47kxN ze+`>TXePfo2$i@#84WI>km{GcAKFl2H@rH3Z=aU_u3^Z?3b{D>awO{GxsN*~tFWbQ z(4@riJBk$O^W)OSc$V{G5Nhooa}wMmN-MV7`x)Pt@_QYxXLhbGyPK+gG{(l`mqp~8q_G_sBI8RNRuT7oV#@uv7YR4R1az7waTq=*Cvv(}+S19|{I}D) z&|B@{poW1&!#96Sp0RS}S=P6=@OM$kuaS~2yryS-M`C@X(M)R`0+nrBI{7ruVB6`z zrB`w091_tPO<#hM4e#AZeOE(5RcvLqf5e(e`Yo&o_xo#!MKdF`u~gFW3ui@hKQhD@ z8%xpALgg}Db@cS;E_E|YcJ*{2(Ezo26zaB^PD&mBB}@HE1j+@d@ZimOvl$7^{vo29 zQsFJOtohCYEyRLCN_CP~(iF!1eQ&FaQ`OCqjJ_tn3L-G=Z!KA zlY}hetz8#&~_nVpXS&2pM zWQd*dT6s9-ModqdYsy5C~?3TE5>zZyKI0E2Yzvd*LBY9H-{N&`R$+^ebky=#Ux(B z95s~@vBxw2)z6e`+xInY3~uBko5(mHXHS@$RYic`8;MD}14CsE(%RaWG7^{Syl0)2 zkwL2YDU@$wRP0n05z5L=RmypXM}LQvC!M=3ucMb}urf(_EW?sdf(!D4&Zf5(GCV>R190|jscY63?(iA?f z#Io>#pHEKwil#C>h*q|k%oy7fg*bz2n3SUycG4E}$YgaozFJr||-p__G zuZPV(c_P$TX=?+VO7OHa`{vP2P8ApGt0fWNH|sW&PTO1s`un+_>QHHiY`3hC?xUZY zZpty&yvhuz&51q3HS{&=c3F6f$Kc#k3|7QA%2&dqupqOPN5J51u8wbB&#xQHqm5T| zuwGd2h(P9q9%^<$#bCrD29__9r$2AsdCz9^@7_suNj($!8%DZnk0uSlmdfc)PUn>~ zTH!lO!7q-6G)=_C+Q>2>?E=Hqk>udm2RO`B<83R>MH!tynwQnY>l~R)OH$=daD3ts~ zCz0Tecth{W(KU(q(;T^$);(L@LyV0^R-eIq!t44S-$Q*@bxtFVdJkHK_eJdC-p9a| zeP5-NL#a0E=+0?K!W_a4k3-Fu^*j#W3^p(Fgb2Q^UpM$*+H=(*l>dUfMTp~Hk*tsni^ZxLUnP47QS2z0He)R7c@7IB3mzUGt;jl7Z`K4Z zX$R2QYD2k>hDy`zh`5o`%fx7C3=`PvgN$v-UMgV1trV&BE^YP%4XJ_~2L036X9||2 z8qirpRc&QchnO*=T(wOVB{NL5cq*!Cun`hdickyr2_a)C;c?rvUl6y^<0)Qq$dP{KqQaUlypHLFami01%?N_uKqr` z0|Mm^K2k#J`+@&p@%;=>u;iI@-_qre5JG(6WUiSVP~)?z#6|X1V3v#hjGtet^4Cz(s53ajNumw$po7J_Zzfh z($9}XQ!R~4#Duwx7As(U(;@h=0U&;{^5**_=Ibl zguTYxGF$k^3=PBXB4ELy;B-9w_rn&UE($0R#IB0Zjp1Iwy$1nTM&Wu(N~;7yn%a~% zPcraWH{K}Gn4yF4X=VIBC0WH{M56Kwn1v7hI@BDg)&ng&Xny}I=N_APPbF)Ww{r}!5Z7lIqg1H=BKz$qTbLLoR<;GYo9IAsk5MzXmZ z5QR$OdP&<==z8`wE`&DMAqxpQkrKhZK@<}zpe7LZJl6N)^FnfN_{?k3tLm-z<7m8g zh(aiWWEQVE- zezh(usF2V_z{Whb{MsJvq#0oVu_f9rG-8A-4xJh0ulmj zsVIWts<#=B?arOwuQycnUr?I(IDIO%VA&Y1R#X*`I1B7hP$VEE#t~$Nw8hwjy1*B> zLu0HtwT+r{L>VTQU0m=qS3g^2N?cuSJZQ#`IUr#C%xhCy26FSj44=m&jgV6dn1ttZ zrKc)Kou9t=WMehc6e1Xv$c(Mg2#0S(B7sl+WX!IvuhTEb?ffz`u_VQ)9GqAMUbZSG zd3Q$5(Q}Wbr}eTfh~aNS?Jq;Y#VAEo>EWJH`+R=O*!YC|MxW&~0w^(VGc_#=M*><* z$a-#|LD9^)fg+Tk0v48gG~AZr-y2YNy)U)mU$V8EB9?;v_Fy3mZOUMa%tbLQP8O;Z z4bMVOV2RREcoI}_!gNlN_x3lW%=IV1oCzP=YX$$kMYl9P@FL2(@+>4Uqwqq2v;d0< zwF$LE0YAt^C@(}T#HS6?girjw^4!5+SmYRhSQJP@KuOd71`G5nG4#m!lfNf$@XIT(W0Y_2N zlqAK>T66iv33If;MQBABJ{+Y7EW#5yJbjZFr-O^-Y4fZ+!kH#4jq&*;uaFU>JJZR- z0^qcP?#%e@cAV$bTvF%Uxm;P;8iaWJz$0Mr_BO_gVu-LuD}u}2MP?SOjRqQ7K5V<0 zoWl~yz$T+W`c%M@qM#CB&5tQIp%Wm%T%2IQQ3ZuH_tPzKZl|xD3T*_NX^nuQ0LOGd z58RUwPM`YGtYr9@b5G#r&7gW^L@w+OnAq{8#>tQL-yE4By`1 zV;HDylJ#x}yS4EMmz{lF4vV_B-nr&=GKExPIm_xq=-BC=>+})-A1V3CPm>z zk(s-iQCcUGdg44Z!hY zQh*fW5L0L%z{C`kH&HmL1clI2P$e`HeDfwdDbo3*=d05!hJgRuBd_NS2`MZQj<|Oz zg*5Ha@4ybfkGJ9mS3Q;_e-VeGSSXqJmJilhRACV(3=0Q$r+bQ?h^y%EX=83yJ@P8dufXf;Q_W6y5ylZ?v`a}w()M5fDIC_ zsTtU2OJ^GvWr$-R4y3qz2YQSubKtwKaHVCd6?+#K+fIz;)ybaVihEPLv&W$KL~_=f zzWMwh!0hhu5z+JE#WQ`Me7mByo33PJPwP$M&B(>Qwi?phQEk0y0f2#`pPF~4F-w@2 zuH7Y)=a=}dC>w=%<%OjnN#A3LZnADPEU_T3Iur?88)%XN>N`lHPcbIF(o&eieEQiPhG`@6GeT>MfnFui=0MzQdt zt?Vw2b#oOJN2%%u)%CLij~}c1{i`LLs_|zRG4A^0W$}0Q>D%E7c9x;bXoI*k#b}gc z@$FYB zdsx|ww*(Ko=nn)|xO!*0Hm+G#x}BwXgkTenwRtFTm;ECVcMLa>MhN3h53sXmQ!O^) zN?a%f-Z`b8`U2S^F|%2r$2;@*@ADX*OF9smsjrvqQ4foLBofo~bnEU;8-2hQT0r_} zY+|A|aL!}?`kX0qD--!3531YfWjg{*8!k~)o$mE*Uvc-`cO%FVOdrT}ofxiuDm-B> zn*6To1>W&yB0n%)=2srn3zeqW%x+#*{X8JD4&>@RBRrc6Boj!BJB+pNQtBP%&ZE#O zO76%H`fehWDBFEm@6Z!}kJGCl==rPCm!-y4=e%+^SJoPH5M@Lh_=Zr=B~wAg5znFj z0|5+HQ2!gmJ5m0-HgR2{iU77xzgYBOC$(&2^ds5M%JfGEp4Hv~;}%Q)z2LtBL5*i? z)4Y{zQo@AqRnLU#RRx}S`Gwx6mP>T;L+D)mla9~vuwMl65i#PeL?$A2D8-y+)XG3m zN~lKin_`QRBx&n7;>6!Em(1%$0`wtlGrlf%7t>VfE@ZX40q=a=-JNC|-(D;PJqmIV z9d)gb#CL7Ud8gHX_1wcscw#O{*8A(%Ttcmt8rn%aP~zN)5a#Rq33s8&=trZ1*1t>> z-(;lr|FHRF^I+!}U6zC)DQWzupXL|{zs@v7`fSdF?7>gxbIH(-9J6Z*O_GybhpSvD zXM%L%%ZhaDlMm8|jKU+r=e@nIAMqso7I*RMkN!$W!-&?4dg5sZB1Q!{LxPx*Z`o!& z*JWpeR!kvKyhA-b!G_pt{IiEni`u&_2Li#4e!D_7BemzYn-lN0@GssHq;TS@lKtLP z&9PMbhrODOMzYuc`P)zVc^0X)7c6t#t~cqkGuK@zn5KvV^W54|T9)qv=%vrm^i1VX z4vx670(~dkOJWO)9Prhczje<;w*}TD3TgKRP2VHEmYP>dDXIMv1FdXdG$FnVe)mlu zHjb27-_M-m*JxNI)FL1vSeeyXciS-Hjx*$A@CV(8Hq_g zZy4%#nDv^8*Vku`LPQugDkIcblR3@4cdwiEabuC#*K}f;f7kE~%T1N{c3Y~v2RAxu z$z%tgXiDwf-C|%kw-{=IgB5!de#g9GvDVfSkWU-sjUplvxW~g2d+FMcma_$42sJ*F z=~=4L{q^NDN?WT&1CB;YhSl$uW?UtCswS*7SFcys*|V%CF!nx)r<2R=l^ zTdQ8Wg3SeC|oz>%HhgA1$ zdsas`lin(uVM*mKw)9T_@UVugXhp`;Ar+b+PVX_!YnKt~2NPHIejUn_a#?2&OeUPy znrw(RQ-7tHP03d8@Ct<6s%^dfzVPp_Z{#}Z$C8Gav$Y_#lNbtO7GZQ&_O*oXZ;7=8 zI&4v82rM+KfWS*}J!PuaU9?WfX5@vFdEgnxKpLOj$=~sN_c@c_CJjBJ&f!Z}x4e<7 zdF5@lJV`Ja;JZDDzt(iTEsgSb4SuZT2T>hJJp4OTx#H76C+kSe?h!RA$sIA@`M3IN zX0PG;t+ZswAAe#diFYG4?9Hb)3taO}IX3T~BI_6NBbD8}BmfV0`j{c~a zAz_R2h$&f3OXIHOgO~>M5S8G0Evseg+x-uZ3>Us<2Pc}(P*uBhyE$E-X!vubUe$8F z+4S3W3fWXZdRvl)f3=;?D7c2Oj${;!eb@f1pM}vH088o}qj3GS^d64~~PbgSxZ%#UpX~ZlBHXyne^0QB|@R9iuXT z&pWlro;AzAr*Y1GmFA+PtQ5+kK`Y8^qHF`5nD=I)g4#@8eYkneAQ#!Oe9f16#=kAC zBz!Vbrlz6xyYqtOXxg)Kgon`0-ojm%{kWk@aI@cGa{lJrnYrP}(&;7PFCc&k<~qbZW%pItIZpUkf2_YF@TEK8U7WBvtv1NN! z43Z8UadI~aC=_T~Nhz#5QG}|lEP{$C?IWIahOmS1xVPwc|8;NbkV7U+ligfgp~KkN zFQN683BTVzRUf?c4v63FJ=a;!E#)y7PnlFeD{%46{{R4T^Ucuq=YKx@m=pi^v~Q&u z>n0RYYpN>;Qf2`sf-eeeg}fHEPbqhoGA^?V3?vpSL%SbIeTh%7bZbLSVpd((w_a9q zx~}-Z@DwK+E_<5x{batIA9LsxX?B~=DQMU-jtah4(YAm$R)nFd*?T;uF47hc{QQ>o z1P|Lg$q?lPOK?isKJTZ4U7KFy$@Hp0rnofOo?r}aRBXe>AyFO}7FItg0l-6}8b<>B zGseY?wCvS{ZI|9v$E9S!wZp$el~^W1NEgb+$d5YCnsv z+$H-`mH7&p?0{4EXUYm*FGLhzPTf(lSepldi`rM$S0%2W*Ae|-A;5PW`Bz<+V0Nq3|yOfa@kl{liJP5`r$%>em>oQ}DF zUKSd7exdr=s0{~-{b_BJ%af%7gGJ6THzZ>v!=hsnmbS_&IHc|p((@&eCs#3X%Ri2r zfuct;~Z{}C;)2x?nFLq zeJc4P77V~u2^}S5Q0~Yh%&=NRIl*^yEbsi8Z4DEnbHDdRy*;(=75-{e0-C};yn@a& zCgF8qMPBw*P}9CE1;WFM9J80o|6-`D776Xht1n3Z(B%6zB~{r*lL~Y2@droIQ+X$R z^;icgg4n#Dl9E(209D{5*cXPtRv|m9b|zbrlWNHKal6ggIk=%FH`%66^Hpz2Ws~Xy zmpLZ4wzdiOkLbWY5%a4+YTJ*b^x;vFmd4Zqb#c~Iz194ttZ|mw5;q8utAUpOa>M z{JYdNtL^y~8k*Pdqj%c#te$n3qCj!Ud_>J~Iyz;;0BV=I_YLMjD)T)%a44JQ5~|(j z+@70E<`A^IMGXs07ke-%V31ZwTxc{n@RTq~yMM_i=6GiPz3L~hw;oqY(3hCc zp*{#V2Kxt+CiYiZHla{}`ceQ8yvt1Z%nHC+DuYMw6=-q+VG71}?z5>dhL9(&q>y!>G%l?`+=yVtMI1AdBM zEv?Gynmi-G;!viH`dMi2T4ZU-JC*&a#G{}VeBRf+B3SU`Z2o)m;WJw^e|}{SWj>>G zk{>OHGQDvL3PQP#Sv?|oP=V&(ft==k(DnEa?SjU24zgcG4S?dnI%D$h>4qYzO&%0+xzQc1lf9!Qrc_2>7FmEy9~P>7{^X}xy!AGX2I7S z_PGW>Dr8}Vu!8epfV0-G*H)JP>*Erss z4#poIsqelnZ^Yo4q#X+Y+1u@^%bhTe2#Ndr&9La(<9A+85%`290#eA!KT5*Vb`~=s z7V^DkEZx6aJ#kD&YN~bw=by~w(c5Z#(9-R_=ak_3jGuf{3t!GTWq=iY7A{Y=f_q_io0RdPwF{RpjU2H`7;cZnp$UhkP^_;ia+r_>t z)H3(t^6hXdu2`tD^6G=E4s6tse7^Y)xh|F7{fQ#;uAPIbz#R{{%zp%Xtq0Ub@M$)5 z9&VJ?OZU1e?>TCip~TFsvA%tiuGECtLA0NhwW=a5U`XD97l?n)0St0_ooSO^NT7gX zP$6axRrIX-XmLM9bXr95vk$$0>Sp1*QPJfU8Xg;Qls%h3LfM>B@OfRpvy{*E0pv*s0=|KJOy~CaOa&h?{}#z zV0=4W5C!QD_tLbqZA~p}PWD{DaM>$C@?|Nv!QXVRX+^S*ip;u(sAe`&Q#4=rLB_v| zGD_$Z(=VdMO5E>p-m{u%kk08*JUMRqOm^VB;$ZJ&@eg|!j=I}UqKHqNr#i8_(WvDx zb!Rx&Q}=#QP76SXXu(o7zV%QP_YDDMRO^r8SI%!20w^kbIG*FM8H;l9W*fRaQgS z@gd7uBpBO=WgpgL(i}Hx+aPStJ!IMZEF90QPoqsU&tIPGz)OPnd`%q%){)PW^?4NQ-X3ev$mYj6bg{h#4f_ zZA5eNB&532r#&kA{=zI^3kp!#1HV2mo<{AlhIlil?+1R*p%Zh1QKj53E|vk~z|o^$ z5IIZN(b3WE7@wnOTf8r;BErMri!=!3RRS0P4WH9hnnf5%yU7HaemQFCAom&1od-J4 zg|2ayt)>sQcxx{XR|FsJW`3J=U#b6>`pTYVBKxMr!;f40O?LL9z~?fU!5MKqJwpPm z+b$zL-{0SB!)>l1hLy(sdSr5;<};wbg=b6Im%El7=?7kq)e2tP()d(Nswf2FJH4-S zT|+#2V2_|U{=TK0_C>=9`pPGi0BDL;?aY4oF@OCEOI9obdrfFN_U0{&ZSrd!imEJa zl(U7O?!zcR9zI2M-w4AX^lbbb@%vS7rH*BjruFzH0LNyTXUSOk*XTqR=JR)2572{1i3W?8z$uBD;s#R% zc*nGawPRUok#r3sEs>=AULQygz!ShFC#S!>9B6OFtx93yE#j(#<3Q|&*~FwGk&+FQ zq%8cO4%B3oaAR4yt0_pM!q{z8jhg(KB*3`&?D@1KAwrmsy$QO$#i`-vq?4J?GP&nM zV2r2<5U$E^Qg#4;J$DiRcYf}SzN?TfV@*g!)$4cJBJO_~FTOb~{r--k%3<35f3J6H zV$y^zGiYLn6YufzC$FVar&ioBGiIfT1P_VOWlIyYK{N+7|IB_MO9djgO(;zy8GU4- zgVWH=V^2>CBWhaCApF%uH>s+iHd{%~UQIL-OS#64gu_;UY>GwIIP3}?{NQTCNySf4` zr^2OYPitQMBX?ve@BTHi+_7?kUi1>66?US%W4Q!y3;*t1FdVrlNjDtV3^X{7ywEqW zIr#QzY_4F=<;{5s?!1)bMpEDD?fw!nS^e`fZy;Ys9WazI44O zA`yN+CkXxe9r2pX8GZH72Szw+GScsH{V$Das8r$xBFbwD$!k^a^KyqxZqPab(LQ$` zZLei#JZ$f={k2YLHJ^9VH}_4Porcv!>4(n(=H1F^=HIyuz8d5zxM{=0G)MOXS{BiN zcep=mppaB;xYiXY%mucdh#+rx5ne(mh#GrkSC+ zi$BwC3|>HAj0yAkSVLEDbgC^_5F?=2=-v%Yb8kL`RJJ|9PaA*+^T-R4>_?qC&sg&E z3A_MulLgXVfpV_4(Na3_Sf~lJe%svHSy{QQB6fUkv%yd}BJz|4?QHJOw%2kgh6$y> zJJ|S;2q$M$_=&}JnrysdqVIRlf%`)>74sxnJf{*4(1`D^K}2ozaRJF@>7ah9(VDlM z4;BmiuS@_Eo6~F+7zf1E(b=(?F~?Ln(V5y@KB=$S{j0*6apgx&-^5-B0oZLQV*TLv zb)xl*-j}qqn*#xd7Gb~ZhNteYW@o8<$tqbQ-~OJ`waEDH=lPAG4jc({n(Y=%pND1@vO}OdSBGx ziz3XlQeG0lTK6#q+d$-y5FwcXa>-KZ5|1p@)px(^k;(KQA_q3p)BDEM zD>_d5(NCsY-5KoRjFjQ!KrtY5IXp_4O8MYod0;asGs5|@LdIujUb!w)6zu3D8u`i9~mlI34B}^Mw20zU^<^tWQNzzp2 zf>k4Spdc8QY$EA|h@^X6crv9?kjK|_I z*jDzMHv1V(a4E%mpap1B(U37btbLUgtU)WwYyzOUwdPYoNN8cnBpNrY-eZJv`Q!9q zcMbFwqI|2dXIMx$J=m!#H>x8Cn!$X3PlwoqgkUo@q60rknD~f@X~hGH0XiNRpGET_G*M#g5lnsQoy0Je?a2{Bj&Ok2*4 zR_CqGWbEVEc5vdq3-0Wo4F{m{TK_keE^B$*8(@0xJZaq*nO~!J0}wQeSh>lM-45B~ z?VnLMEtjKhz9CKq0N__vvU=(0*uHXr0)!i3xE%NgezQR7>%Q`3JLYxt3+H*2*6cP^ z+u0?4-SbxzK$R=w|AS9!s^Jxl=e&P>(lYKMRiMN_Yg;qPaLRaH(!HXI{zMH*d5H&BaoH1)1_26q_X(%;o+$EpRkk$;;`+=?%cEl;B@kY2v7%}<^L|0SK!CwYP$iYotRGmlG> zdvyy4;4UkIGg%M8D8k3>VAX+v;?EWLfWj*dV2yx^mOAjCXh}>z@gHfB$-$D9Jy@Ts zQX-OHlsiRrH!%7ml?|VH3s6AeSxfuX(`JG~&TW?_vcv;q8m{q#x$IcOJn%fe)r=4L z-+WpxsVGK)unys%MCFT^l}RbgUSC+<+>^M8ZW{9tq{_M%fRWCIzk&XxTX+PlS(Lr} zY_~Tw$5m?4|LxQ9=KTBmNzAOob%2(GljA)JuJqh?R>!hZEWy_kpb%kV`=m#BTc^BB zR)5^)<(Oy~rk9sud58ASW0$t)PK_0{HrKW=kQcyN<@uhOP5My&DM*3dSR#L)4t8^f zTXg>Yx=03qwx#PIaxcDhKYf#(ITRP-_f{{p(s=0M5Bbg!s5;v-x2iAUPiO*rIMz)y zo_W}1`!8~9^)J-M$zPpF8U{AuOt;5u@i?(z*=A){R3b@fztNa~Uw8U=pr>F#k0*G& zQwdXEs;!jo73PPd4HeuzFVlwj?x>`5NENUZRS`@ju>E?Yc zwY#fVo2yvWI*AA!I?|I@M+%6%7q11c>UT>h&B8pxwzg@VmBh{pX}M87bDG13J+9H=C}a ztYLqaC>oe?+h}6u-)E;RT)$aZS~UmXQozd*$=%y~%?Z6LpG*v&iVPxc3^HUMvKIgV6x5Cww{hlv^_JO-~PAqpir;bg*Asy)6s`&O^_c_&iuGEUUjM-HwiZ-LdHfh+z6!0k+BuE0aLO7$F8o zwu0uAy1a(44eUwF?z~9VPN}Z28u? zd*Qrr{MForm;FR&UorCPaLE~U;XaX91Cn3;oC~#}ISw14 z9Ru>S?SY;dQ>i3345o{O1rL8##J#VKLmF?0BT+c|804%kL|nXFV8N;lWos8%3V&1v zYX@yfax=P>0w$@Add$?EMG3X1H=@oGYRBo2EJ;o70LcSFSQ>&{U3{i!oJK=MOpahGH;{nVA+7?T)ze1VGHpq4)7#@b15ri8b4yu4 zb)=#Q2@4!%RwF>~7U$@-4??2kwYwi-5pPs@q4r|{tq)~HP!%2F=8F{n%!?RR2A`m4 zV0dWJD$uR!6O0Do55ttW7KQV&fguQy@a3xDlfl6vfPxR#QIZ=Dn`mDwz+=h;gU`VN zT7qRbI*wCK=|}1{pxvB*Jc0 zd|-P(!`HStj>QpyQbw4+FwSML0N*~R&F1zwIHf&;we2qf*`Gcf9nvqi_keA*8r4plz{p#(TI8j&j_Um&fEWS`xKnpr-Z~?qAWuTQTh9V8JvEa+F;EU z8sq;)osX!;OH)O}bx$d*oZW*+h~E5wfwkiQMdzdRmgG5aKj1c4eX67Hc34Sp`vp~0 zPa6kBLgeNtB{YlhUnVH3r?Rj#_i&p4T>33UNvFMJ|2+&$8gH(ODm-Y?HqgHCri5Nm z-f*zBm;C(pMS{TrQ0ZSArb2OG@GD2^VJl$S%tQc*elRavyE7I;y>E2IlZm2~7rL0U z|L@XR6g5R_1wOXT&KO>RD3q_~3l^l8x62%Ufd*8{nJT=u`dwr#Dc&OJ3Rs?nuA1C_ z5Cse*0@%8*HP9fEw;w^`810nR4whUCafh5loxpqp!JjbHEh?ij)Grx zkWCghoy}iYY|p<6VlE&M1M4P@G)r!lKeOyi8^a9`2Tg1iPbSD= zc*w`V=5vF`wzN5r;#f|kxWjlWzq1sklZANk=#n*ew8oTS+S@5np0a)YEDU%=+r^;Z zH<9Worh>XY)^cU3!n?&MV}Z1n+}`bFZ`${UNd&D?Y!sa z>MQa!r0x`Gfc+ul_{6a&ettg3Ju7=Eu$*sgoKlOYH-UuRa7Q9Fp0nEqpVI-lAKpu{ zz4eWLYqd@g+j-hs@~wN$QeRhUcvZ>AxgtCA6+|>wK8oKz>N6$N(|_JK)FNH=(ucF< zfGwnXoh(a0axiZB>)*`1|_#XwD=#_OQ>%G}=zzX|Mh_EQR z>&?-JLih9bR@>q0 zK1S!kp+!Vfn3oKZ70Kh3@{JYNbu$^Yi@e8gv}8L$+(?)B_`Ef2`=}ZD;tq;?W>P9HuEP7Dk5m;^h8!rbq{Rr|DL@Ifihzl(qpO zMB11hActlvzR!`)$%@oLJ|5P5gTmtiqR$Uu;$aRo1g<_+cy9JPi%eFIVxAK(Tw(Qqtp!i|DBU9*sQ5|G6437bF%BEUp*Dy<7rqgP~;d z0)j#a5ODLd-?3^6ac}_uxMfaXTt$t@mBCf5MwhlBG5ZT`MTQWu>++~zA!sl0S~ zQg%myRT1w@E?C~DDQvIRJeGKicuO4424R!!!kEqoY2pUrO@a(SNwxRFiHo65@D$1@ zmyNMhgHRj^N(2gg9dOp|QkPuo&eSR;&xI;PiGU*laA4`V;8+lM$$f}j1`yTVLf^68 zgJ^0uARfcX(VWF7hzMAqe_*fm@zK~?V4Wi!R#<+j<#NfVp?`3oThAco6M)hIgh0w9 ztMRFbTm%85haOFw zQk!y%fHgOa#!XQvkl3f`!(pt){?;PIiHDZ+BpgML8z(!Y37j*?b|hmns8;gm5F(VClCPaQTB+FP?ZCx)S;zfv$TDf-(;>TfRM z{h?3iR3nH*y@9lWf6^ZixSwAI2O5Yjrsbj@%DvvNf|a(2LUUL z)%pQEQ*}Xt^$-#@0$ntSm_QUyiKk1{QOPtnVLFrk4W}O%`kVl0?vl#b*es5-DS(wx z?{d|(p>`RpP&ESNZPdo$R0HcOXroP0+{gz&P{x;FyUU3;Sg2#Liam~O9|NbD#{rg= zl$wc5F5omWtTc~z*m&J~s*?ZlZoh0GjGYpP3D1s9VN}FtXF)N(4zHA0cSdymn|dWs zZW7Lk_<4>fZSgcqSa)nb%oQ&;`TEJEw*rC&lQK(o)v2%RY5NfphxPro*M0xV%D6Q^ zQZqTztv|l*4jnUgJ>=ryeXS1=?!4*Tg< z`Se?JuUJP{QH(u4ox`S)VYzu{Mh*F&w_3uw534@US4Gx*^BA^Q1AUcptp5-kRJ$?v zFfMhIzk14vl8UCrf8DUvr1~8qB}aujzTxjkS#-i{PI1As@N*Tf?MbSl(Qa%fzHwC` zTSLPo0u+mS99Gry_PDK>#rav?C+7i7y{SM#mPF4tZ{Ddd9QZ9_N*c+K3VL^FJO%kw zwJVKF(fjYaE%wv(bVad;#?4mTlJ7%UDTNUR=LEoFunO>p%9+0US!3{0>g&$ywxJ*M zVV6cX*S?IB@9;UjHs&J+1n7~brYP6c?<+6nAGqO+bGG20SWcqy&I9FIjsNoB$FQ)~ z_!Ccc*4mF^WSO4T^_rLrWaGXvstLRkai0(yUJ(@FHdUowQd*MVv;D~?Kz$@h?_zmd z&`87=+{Fb%w{zlr^85z-eK#r0rkbM%Po$;W#<`{8XJc%Fvk4MPOric>%XxGD(|xAt zFGa@5g^ZH!?^wht?Z&sLQ2oPfopf(926u5^oo{V77g_JzNB zYWk8-9>eJFi8y>`5}#L5o8T_zDl*okcxLm(>T-9d`RGt7`YD~qrbT8^;b?>D{kwNN zB;6#^24}>oeNO1B2s-YvH>}l^0rmPj7R+b6xzce9+`-Kk-!;WY>vir*0+$7>KCU7X zX$sq}Y)M$-F3IBKTC8=*LDY9F-cj6`YQP7O3*euGghZ1b_6%|T*f)4EY$bAqk*(go z9Zo!oFwh5Fj;OG|*Hw#C_%8aZ>64wAZPy$1 zs?X2sVkhQ-4JoQoh>sK?teH1l~IX3o}b2x>Z+TnbaLHl?ije9x*%pzI9fdnbyt;df& zgx@Z`HS)kX6`XpJ$l}@Ep`wbnS@{+3$HR;Kl$RSbL)G)4ZlU`qQC1yLM9PZ=%#wWn zAQg9$ah-lOjejNk^k$b(C9x?qIVw>B_6+0Fe|;w3cU`wIkQm>zDOS;V@=T21_=(|} znMS|~?jIip`Sn5_@q;D?LF@Iu&hSseZwSUY>G&V|?M@NQdYzD5O-{$l3$5K$|8|w{ zdGiN*i>QneR#{elCs^mc@8aw_nAWQl%6$@|mBVe@pTr^JF#XOh$3NBGdUvr`?(ZLK zW~P6t%^ae$GFvLltw(IZP7|#k_y`3SaR|QR^>6meTo$c2>_nQJS4+Fpr@ZW)Yft!U z(hj9DKa}RY+LR3N*~KoDo{W2pmrqm${?v78S~9F?T7HJvo$e7|2#%){&L#azy3_fc zOkQzRWKG~aHX~Wiu6-ZdeB2dxypz$rK)A`~((23SSr|khKr3Yd6MP+#&5}G)F#UAk zbzKoT1yg6D?D;W!^V#9dB3i}$prA;!*L?lH-L?w+DrHfI8%ZeKbhg&rYrfdq(J|Zn zv32kqzvpOVMKG6#Fr=)uLWGzG@>k<70;j!tDN1qq>OUWmb9-KgSnZey+BL=aO?%n zE}dQWNvHPyr0C`1mk;9*zDuq--p=0OKWilQbvt}D^gi=)U$qPz2LOwNHdL!>+>&~R zu_7G$*m&Q0jdjuwReslUkPrjhunI z5s*;y4Dh#kg zc5)d`{^>6-rh9WdM#sgq4NL)I_Q&#vvw6$w)RXkWe$;2Do;fdRSf8LoOxsXmw{2}0 zY@U-{%&umy{?@_v}tJuKA=iJ7^Od(%dviV^7a7vFOkLt0%jxo`3 zk5lP0vU zTws*(!cY(3XLn`LXXXL;??<&*;jC>{piz;Mg8*#!elb^e@Hqh=*5XY7r^IuYp7;h_ z^R$~s0Z z!J;r)Af`9wS&upewz*J+dqut=Q(&#~vY*Qao)Oa*t(LH!vzT&bX1#UEV%cyugkQf> zIP-uwOupq9;@Wy5rLVX!fLGPDI*IauN zd;&Hq67wi__23nAXW`W3`=+!_PdWCDqcF`?8L(Ln&8P^V4YS}<^ZH23+_HV=xfV@o zaWq%BHlqFf6*D`Ja4h@%gu_*F^O15rn!D`zRi9_RFqdllJ=qGI+2Iu5V+Hn!FJmr% zVvTfV_-!WuYLU?JMVZcaVcRiHBc3uII`0|#*fZcrz}nz@)rI+Mi8pCPVjE)^ip)ay z(tXOrmVJrZqQFp_G3SpL8}X02y1PdBO1LNU+ld*^= zcu;Som}ty$bGT79vrq>hJWcfG*T&P#BcIWp^)_W3_S`GrKKR>`JFMNOL`DBZ{(umxE zp-Q<};9o2=_VhoEAb9TnQ*G$o2g{DGwDbLxv#MFIAG9}DOLj`C$`lmLnk#FA8Z7_gcuo%p-78v} zqP60e<_IVplE%V;u9n^GwXcWU4A`xGw!yQ(_O~byfR$c%lyuV~GJ55++Mb6u;kuPIO&0oHo{mKSMujolA{YFT)g<0USq*td!&+Lze^`%#^ zlrbb_pqw+Ocw*z7rcR{Q4Ck2P#PW&14kgsU02y(UF?HoK3F9j*1ynKw|!gf4i(iCO)C6E=14g4mNeWzr#kR_>(U6bH$Su@DBm4h*%oFW?WW?f$M0)N zfEV^>y6$~2F8;EvC_M)UTX=htxnFEw&jXPsk2-4{uN}Q)m7Fv1JB6ycdV48KPmcCI zpS+#@Lf2Sv)UKDfc=8JU@GmY2^UF#uDCUIu@7v#-RKxVuzD{8Xbg-vO@x_PIyS;@%JbA|OxJFON+7IVH z?v9buYn?heZ$jw1lvV19IRXtY1irSP@@D*sMaSw{FTY$ZKMU$c(UFNSx;nn)=C(&j zPqYc>F7lE7gQ5|{Jsg>+&`46@eL6n(R)l4kJEPvECc4&d7V|)MZg#aS2n7vX=wS3+WrB35B1~XtlQhAQiM*X8XbYD4}})-fC@D&EE;L zk@kx}QSOIb7mfw5@3BlsOo)K5UaYM1kH0+#&;q8Zh?N} zs&*a$%uFN0e@8o>@7qmWtm0{=JS?ijvk9;1JA;mwrIi&DQ=IU7)-8Z?5gz zyV;aflZwux?b!lzf{<8L>^^>VVtI3qu{TLcIiKSTSSoMLpFv&ZoA(ym`D6(0t7awr zQlDXUgc=~y4(bY@I|`xU?&#=!$h`CyBO;@Yw%Yg+|LghdX-k+> z0bN0j!(uyzrWIoue-Qv+Kv<6ZQMEAjk}>|uEZ|c_efj+CrxiGi%9!5u<&^tDm&Z7rP4Q zY5W{nKb#`Sp{NsIEL#!`aH+*dKG*5gxCHalLJB$CW74b#y(?ahJUJp>2Q%Q@izcw3 z5v&owBU%^MM}6uccJ`WIDEqck0-x;_61vaU;sy_H%t;bE?ulPyHFQqZ+v7bSH||W- zf8}#>`))7qGid&{TKXJ_xg$6Psc+bbtp2L?o7t|k8u>27S9T0V{YTYXzAn?A`Sgrt zJi9-oDc0^+HBX_UX^%*Qsbsp*SDN8Olu&7ITKuw}b5mPD5uq^A7GQ4lN{b|Car$ z<#LJ>21+PQ3Dp{>cfI^9Da#9AUK^-fF!pHGrsbe4FC=<`#NbHv382wC3zL*bN`-=0 zHVL4Lb&K^3knLL(Sg^d{+WI`3*Mkm`(!aq#l*q#~!3z$W&GY#PK=?Y3omWhO65*4d z%w)kV2VqvVBiEl>J+;)-H=<$+lahy%H?!2z@Oywj?z$_gnHQEztqW;HSFkKvCm!+# z94KuyL5W?>(*$DCco6qTR5c~uy;OHWB05wiMcSaFiK@L8}F)qrMB=k~Yr>%82}$rhTfI&kNN+?Oim z+5{vxlqw2uP>sACH?ETl7sZaKGZ_TBcFtWYR*6}p5DKO&?Q$0>hXJN6;hNDzf!|ml0q@tt%9YvL!SWacI8o4FfIdZZI{1NRO*X6>Qy79&bsYcrT zi1o<#KA_^=yWOcTL}a6UN*eEmdb}ilsuwy!_oo~dHAoJP8jvv}6R1jd)d<$Aor}^k zN|crGzMzM{5c^?qIx|Cvjaq9bSl#N)07&~?U{;Mk#CgQdPCcwIyF0Fs4JU6X{**M4 z3KOGbWz@-p$kK-4SI&RK{r$esW;WLVjttC><*Xv9*SgGGz2?3vV4$Yv29>}n0o zW)+v!ks$=*r*Qh&B4Dl#(P4tE@L77uba>@TGa@Db+f3m?x}OKR(ZzK`J=-rRx=`jI ztnpdqtSoG+S$!*@Q44w-be8LlTg^NMFRAeqZZ3E37FL9TQ*ZpLZ$O+~e~Uf93P^aJ4s6C^l>2E8ei=j8zL5 zaU8gCGz$h_HHxUdd3jXPD}h$QpJ^Ae|&V;AMY(@XL90N_b`uIwj4Q9t<~1P zM}JM}xPpXrWp3FIDhK@_9#|?vHk*{aOc$ z2XluE7F!FFyBbP~OhtKVvPQ(bU}qL%-@V`bni_@QD${`NQ7~o%vy#AD26C`1aq=Uf1h6 zbH8v?CH(uaH2gGvb>-r_pGTWiV_U%s$9>707D{=vi=O*c#{XK_?TBZi*dr3(cGZQ; zg~`KwfQ~yu!iU^ky$~G*DIcBE6Ristl|&7}sc8GXNs>#)%99K*3w4!xJ9joPKqSp-s@%EPHDC3+0%&pk)D=DS71f`! zzeHRX4f6&aB9V&JzF}4Sf|fqF-**~qSGkAShUS}Huo9R!Z!dm!gR-IP|H=kbP&TA2 zwQ!{aAaRV6Ekbz00e5|Uy~f+VZS!ae&l5Ng1(}+B0JtMJXkNOJJfa}|`tRSY#UNN( z(`#?R?$UaBYwv!vjG|iDsPOW!(;K8}$LhX`T80R(-$5QCF8cQWoz3(LdGC)3{XCeB zjEyuN(M^0ATv4_tU`?57mIukqGK=jtD=sOTtW@UX0NqN&>9@`+!7MQ$rOh$OK9NvJ z=pC+{u7E2Z&E}UDn$@mS8fhVS4kBt_>a0;zCXmwyhxNy2;S*2?ORmH|x#PqaY&8CB zt~GX>XZhP|+MOkrl$@Dh^&9U$bVw)^!lI>REM)?f(vhJ{U+ig8dpPGGk;2#em{%M$ zek?15y~rt)?(`{Oxc_}t7hW@UHz753!piYZUxQiq{%H^f0HTN}h(J3J(0b8E-xumD zsB+lPeEssR6=Kww1Mgyh21h!kCZjFCo@L5>o6w3{*6`GPY|~LfR{nF(%B8Wm`8<%E zM-=B5MSb(!Gi#sy{G;(EnoFDeUOhS z6)cNEJJ#0oOW%uwKSaYNR9P+z!pfR<30C_@RK&!@K~&uN_5;=M0;FSQyf$?}3f^;N zntRU)CS3Z#NC3a%XY8$fR&vWD>S2%93H`kOM>Y+Diz}s0rAse!JdNe|o%lgeMpdM_Ga#LYf!N9`mS#u5w0=K~r`eUgdh9r%8 zMFAQFOB!!n$*rx>jkPwazSJ}(flY{YRHyvkZ{C~pMB!$3JW5#oyi3cXflg{FE&BI? z3iO%Z$vK}#bA(o;v*Kn}gMTrxf~XR$#nM~t-%?g8yAUV%ZOB%hh1jC24#mNw;d9w0 zOTUCS`_+mkS9-{eb87mLiYhg_lZYUF5CfGvr_eI4n5At*I zSt>$?_qqvbW}~`#BBW9BWnVoxFvSHvA6_eryz&047lky!_xD@>))`rVW%;GXkK zo#;FN?*@AMv>Y69?^_zq_XhH$ut6f+eI}x6DDLzOZ}Exy8aC}EqL#@+HqBp?mX;34 zH}+H4|E(c&b^otKP#=2}R`LI81k(=Gq{hPT-6>Ebpr==vMr7{7)>?fI0^KEZ7QD6# z5M}pf$|amPI;U&mw0&l7aV)>~9C#&TdJ9_zxf$EZVq4c?67 zeK0H^Hw*zq<9T*BH#P^neojqXt*S!QN2I+rL;|IcjtU1TFmeOW<^R5WSEDzp=QdX9 zQ$OzpqfzP%tE4szYgz)qskrQdKc}t*pNu+~(PlxRwe-I|9`4k#C?$9XUrGoSZ$ z<_gxKkwXyNohv~`>Z*Qd8RQy4W5yAId=J;p<`9myvVEd``LxT&asL6)rYP?r!i-B}+1V+5zg8VtD<>y+<~PO%i+uO> z6KJ=N88*Ko%M0M8DuC>!tWOcT0&L%8Sa8vG$w1@Nv($zseE&NuID^J~+JS+Q>2%@=ge4svEU?_=!5MtukR%|O6=;ab_A_89{W67J!M%+`$yzK@QAJVhR9l>8E&WUT+u^_;oD|v+AEu z^Y1NxCvo&5P5&)o&#g{G?0p%JG4gak!NHXfn7gv{GKF=zl)Gje0p5H$i&b>J>7y61 zS?Tgu%Rb|5A7TT`Knide(vc%^VG%O<6$WEzA7PoOK%3{^^B3p8E};LvRz&JT016|6 z5`UhYP#-jDt#ME@>Fob!wVvj6>RTa=LQp4CKWfh+^^JW7w=RxmvX+-VxM^q)+U5E@hzRWOvg zPy_XyjtU?_MWYS$gl0F`-B};`A4sSq6{mX zI)zZ5>)9_1?qF!6E}h*{fk3)=)19yfFU*ROdrB81Eek} z=u2)MDITruCcISAk;3H2&14(%x!SmzKl8`!#gal%x7j-@2Gl3aKi_Oeztbza9RAeK zuD3kaF!kNgKfo3GY~pJ!5^yFQ>4p~^o5u{9Gw&(Efp7lrhXsvYPPgD!c0DL?`a4d9 zBfT~)G+lXp`iXNtY$~S^68boGi)C+=pPh`ZJAD?}9|t_zWFv)AMRTokb%hX^G9 zG;%oeSKVnr__DgrU&E&1r;G*Nmf=01ooD-xz4n`ueQK1G{>ta&S_#T_)*N zug*r*TDXuY0tPzyT%8*QR>%GGbqHxn%#aE^d5rql@>xy!(Y* zt9Z)z+&ABC?|&~ZwuLn<9?Ufm;R_!KKIbrsDk$SHsz*{wg>iQ_sFDCD5)mUIT6Lmq zOsw{tfxIW))Qnv?tN{RTqNahyo5$L?jvYLHO?5?;=&xe~lN$pWFCXa7JgFfRn^a=m z1$k-krv>tyKqVsLXL;LMjOU;|v-J;eg<#h-H5K{_u54!f8b@snn zou2gp>09b#D@v(q%!!`9j(2kuu#sHx*y2LPXk}yY&4TA~=ncB= zb+mW5{`qTOL2q`vc;BS{Xl2lF!klllWTy$_`Pi&$s-!24`F9@W&h@I+_QnDX@r~;; zM-pJ_Le?RYehujq$L*g7j_&9|6;oCbF}?#(ED4EgcV2nlv*?j1tATbCmWuv{mC=FM zZ;-V^I@lGG&L2Khx11|bcRcZs_Xz<8`}+BvaKIVqvBpCXGR2il2z0k7t1CEnyK{NbL31cy8UGz@1<7CLF+xUf8Xy7Oi)f#>lGGN&}MOg?7U zsV*}ZN>JWY7i@YH$YK5!(HqkETdvw~UiJSlF*0m)#qfQ7947ay z2!R&hIB;OU;F+qh^Dct@^QsVU6g6dlEYF{B7tHf7XWdE&BYX*AE3ahPs931p8nrPk zl>dNAU`_y$l?GuqgYSvUPi)^_X$oQRt8!AAvWokds+P1+en>qXLIbJ<)jMJK=QVb} z_|#bhM7|~?RUiq7{sPXX2mxcR$ZKpYNGcxO!tAK%2!f=plky{Zr#R+E-0MamHp>Bynz>S=3 zp*O53Wxv0WYe^}8Gk+D{iB=Xwwa%Afz_Tyb?7lk!)G6a(r{m_@M14R+7nY9qfMsI@;Wh>- z#RKNxp4ONlfz%5a5+*+K9DhR1#6tZ@~PQwCO|6L`{iMBYMdcCd{sktSlQqRe^{i7lLC* zS&&N+^-Ib%*iPmnhV+=qFJZ1CSri+QU{Y|i6hb6aJ#EeR4g+NvAtYMCq=;+ei=x{)rmri z3fQrnP-7I@e6`ZRafcLgMhlP<(u5&ua6iyS5#?9#LlLu3ql2m~uVwL>0dg440*%39 zu(2a&a1Gu(PL+yNXiL&)gTN`SMYPE1v(RiTHS!dxZ>TyUb|Go2ui!*PqzcSvW7t_9 zQL!{}{yu3tf*h8XJ~`Mnr0HOpunc^5DSZ)5*I<17QWtO&3|n#rph1Yhs72EIc&;X; zO`D6Q#;K(rg{DSCHqnILst7IzLwq3API3kWfiqEwW-?y;tLBB#i$pDf_FHxI(yNhs{|;MKXnv=k9{g( zS=G7j1FX~&%~Zm$)sA?4s9wN1A29I^LWN5!oF4n&{})*VnFh~^Qe%Jri3O=ZFF;1c zneCq4_P!n)8Htc#RR>PU4iqcFKqOM@WCg+s^hebY(J+K(HSEBac$);uNScz-=uOTn z@a5Y9cJWp*lo5V!6g46wri>t}8oPTA!0_&-qq9qyg9PT}g>>se0V6(7hSAt3;fama zrKM;0PnFoH(OWHJPt+dnGG@q=pjz~(W2x@W*f+<8bO6EuIQicrjqeGfnZ7^wn~NlzoTcgZNAT(8tmJa&zQ)+e|E)25f=7L2|Y{- zDi)TMleL)aJ1(+frg7?UU79w{CaAya>%j=*&v05wqjaFDxH0F=s4 zsY)tIFfU)74DCPghB6^~C`xkgaEyqMI}(+8&2`1jN3WSi<4z0G*9*8X`LHtwSN zeLr(c;&zZ@nq0O8c9^@nf2A@3FIZAXCUUS)m1ZqQm8;ajj0`K#57z_jzs~a0Cy2>< z!WpmkD$GHU!XxtU-rir-XA|lvx~Qq5w%mX_we9RiG{r4VaQ`U`2D4_{$#xMe4@KpB z*Q>;DLd$XUDODXH$PqR+HI`d~VRVg$!Hh3~7{4qU7qz$uFq+jBZO|eq@Q|5IorphW z`x00xY~d3Tp@_nEo?i2}C;pFc?oW&ohCsV(Df8hS`61Pz`|L9mDzH3Y_ZMw zwIa1b)xukxno}8PmxlPb#0SI^msN%F5h7)1z~d$WzI{<5J{0nBAu|@G{T6q)x321~ z*xELf;Xg_^r{5ngE}&tRR=H&X>~ZW=i5P%hVf^2CAjGK9*dZZ-ed*Kx)Cd22`Uypq zq!bC6Abjw4C1v<$+$IxZhyL$W0s0xg@vwi1+fFM?tR@Pv+jBg)Qr$utCrg0!IUMp)sfctAC&peZmKimc*nag`R}@ zM8w~&IxCI#d!uv9owm4_=0x@@uIEPyOuwevuXFqq;R{&h6(R_PTKY*$VeS*1fZ<;9 z?)rmY{yvb$LHvutY7m)hO__mvu$EI)lq7m4!j~ZY3m)t!C9N(Zs!%z?-P7RzslK8a zgw3aaAmu)6xE=ggnGf@&4Kx39|2b}yEOvMg39-3)S`p}eHXy4JD{Z&FGtVnG#%bCV zEiJ{%q?FJiW0*xz<+TAmN7`kog;K`$lvFJXaYlbR$x{}i($GOMPk{*6Z1^fi%WDga zIFq_-Eef_y)?O%l*gL!oMY3g6x@D<|Axj9tNMOMOb%Yc&s9Ld;8;aeiS75P$uGoFy zc_)pi_Y5D_9d}O_H$*NkycoMw5)AoZZeYq(UozH9xOGa1iz1B>BLn|o@sZSsVhijt zBD%B*@h_4I-GRTWh1QwWJ)-2+vn}W~1!6ORz}W96G{fRB+nwB zZ?{L2Z;3&Vlz|3C1&2;)%=`k_uQ5k5(zpy=l!k zlsCe-M#fK9%Mguru{;x=no=th>TR6dP*Nuw0ad%SojK2>>^iB0aJ;ri6Bxn5w)%Lg z7SB2lUs~~Y>g^Gc@Qg--?a}PeEhT$CT_z1$eB3Wk;k#eq*s2sUjKG&AdV^`rU6f4l zEsMGM$ZVF-q}~dG;4?ZVB4%~-`;3A(uW{^aU{&ZGP4RC82vl)`j8^m~h(t1@( zk}dT$fmtwSeB4H78{%=K}SEi-PZGUUR~p=}2H5FWnUp zzp6v)z|Af2k#Cy|@T6*8_L<(`3I)?mQsUMrS|v-oB~4}Cw466=PNnKw5YY=nKL9zB zOGGcxv%W<;H>Ie=(lU26Uscag_0buq4}xMU+_=i{*68a0l`puD+VgKaZsQ3}j<>p#7$26V~X1SUHL zG-lmlJR6f9Io$=L4jgk*noxuokc@=bt-AaE92}yxv_-X4Na!z_7d9|a?#dlK5XzFm z#1Bc8-ymg;R#nJDbs>FO})4oCdwXgGE}$f^cPq z;>c=k-OZrGQ=lXX3Ry|Q=T}lzS^K+Ry|pGrv)3Calmb1Wbmf9JdbTmLlcz^OU zr{irGE7rAdb?YJdvfrUc9CaulHz%Ht-P5jo_na2Rm7hJ26+7BWph!P4X;|zCn@w*U z`g#?dGT*cI7=dlzP`xzx*Mm(#m`B1PY-U(DQu1%Gamw)LqlBL z(6j@7Q~yiGGuQsQCm0HeaR5P%M-^w4mP6Nrent$GYeQny=JUr-av#R(-}?l50(7;-L#$>kATwr(}|C z>&(|7CaV*|oDRJ1N}@FFrxJkMrI>dkfaljnL4cLYthPQaB-wv?^)u~70ZhLiffc1SDxy7qi5*xsq$TP zjL_??9K6$Wieo92!Lcce_BZFR+3f$T*?gP0-d)et$?N;a!CjV_6uYjp6`PLRatIr{ zr?a4(Z6UUy9vD70`!?5R2W~fk_SCMxXK{OK`}D6+NhiARI39jyvzn|Nf8r!p2hMiI z6Y(jCLUmnS&*K|Tr<_coBCMZ*9mbEtMFoFLWFSErY$8b&VI(0TAdDZvXfp-tO-+nZN^b5Ho8-2^6Wi2<5FuD;D_$`oq zHI3zS`1zBPidsRz83OyOule3y7z8E*=3Xb$SR_O_X$Z~Ak_6GO6;9V<12@5B2Qj0j ztug8u`|FyHIwX_XL8_0#n;5BG2t`GCNy=)kka#9*DRm8v`YOKv2OwGYU>L&i@7S*l zF1EavUATnn>mntrF_m-?|W3W1(R^ z=7R6pR|^v*End%aV)v}3k)1aN4z}SVEZ_@$mgN&JDf}z)%flnyqjI4pLEQ-J#N$rbT5(S!F5T3bh0;bzPu6+JuJrs8YdC{9 zfLGr`ztZ4)NXYx}>t_GC1Hq$4M~pY$;u|vzrXsN!!PvILkp10>yj=M=T+eILj+RD$ zykBtcZ)tqk&O1MIGVMKd)&3F4wczPkSknG{xV(PH?X*C(Q!x;Uu35uUm%hY~5FJw6 zi$mV|;`K^gvCv|ymLA8^9O-kj8ua1E&^w=#)5r{NPo(tz5(VJ0BLDt9)jrk?&~>C| z-jXjHTr%edtTlwmNL#Dtgv;yek>k=7!0ZuQhOhD|P<2!|AG_oyR0DNF(!ATWUk0oc zzVuuvH2Cp}_;fyIoMoYdL{()9TAksIv1_iugcF+v9A6xpZkae3eLZq}gKXLpSpkdz{#Yg1584vcmgDfF2`z_n!++rCW0Ik` zW@r)Ss~)~LC%?AF z==z51xS+5g{Dy>cbxD$wo>d}wl3uYE!w?>$XF9Ld*U zJYN5zu{}OmO}|Ums`Es9z5pYU)zJa|`Rl6_*bGq#iT~wARwI95*UdIR|J?&b#v-f96~* zB1({E=5^UP`FCd|7m}q560e&ZsEGQA_!!_)N%WfFE%k_TaUpYY_-?$1&&NO(rPoGi zJxn$yv02Cei(Nt-O~D>{Us1$fHeC3CnPZLg1=`o5x=T-dtAv4=y5>WFGa9PNZQCiO zGVJAc_+qx!D8&BLbh5PG=LAxMDr zQoxqq379aAtCi<9pp=|kX5lF0t-qOnCWJpp?^n0Z$EM2O_!zTadvWb+&|xmV^v{I& zkagYJ4jDwP*%kj##iIby;UW}WWo7EH>V4v4*6pFJuh!!wIt9GzWh@*vt3hu?{iyO! z+5nSMIB@NTvP?p$YX+&h@xqm(mYxuhr5PzP=y?#k28&LgT$+q2-5Q&cG3uEnXO{be zE08&SPIeki9O36btf!_7QszcmnRKDjC8O(}mjYH*?c&YPrTeWVFWNU!i4Z%B^75}e zG$(EkA7=qn14>5YfZ>nC$8)&KnAhqO_v@BAXgDR+wTMgH*Eb%jH9#}<-*KyggF8QR zDFY$KRl&Y!I`F1+7l*?U<`$aHfD;jJ<=^!|)ZYXOJH7eD3pGb*uGTd)!I%uvMWNkg zhSW2UGthD(_HeVjU`HVWl;`wY*?)0VBIKh<{M7F@Uu#MZ&1pA*Wv(jPA}Xc7JAl2VOF1=IMj!&+ot~aXMun$e`Ld6V(M7oA@FGL~YEi{X8wFeM z%V2(4QB=K#iIQf1^AV%Yq%PUr!^5q9Uq|ypwEv{SYtNav1Gib>TUM>bl1iOh zy;cYt5Ektn{4M&g1&cpJ%wI75uy4Wc&=wgFKa5XPBow1*qZS;{FsT^InU|RU;}uvW z-~>U35PLuh&aTu3>Dbv+-Ry4le$d;G8`wl^I-rW~*J-sO5%WBHE2V*HllS3ydSd&1 zSPOL{MYj~vue8@^;CLHSK3Dz{I~fQ_l5F%YmFPZ%nMvM}9=En)7j)*}tCuy9sQN03 z1*ba(IL`~bwRtz;b49vKoTs_@w9!t+L znzVRt>~m^m0BTbo`x`NAO|_nMM`lq`)Ijc_fvu9Js?S79KzAa=9Rx`84y?FGt*5xy z)1Ak7_*Bor2R0BXIND)6o>}ozZ7n`$4Vr{`$s?5@%c6YuuBfFNi$}_Q?3;+UxM^l) zBD_*{4i@hk1zAJQw{H#3eO0fuUo}z?f)*CRBt2<_w2A)SOhUR3b zZq`)AJ=&^g8|SBUn6CAhto}2g!1)~^u&N`i;@}vM(L_{pAlXPGo9NtQ zHM{04Y|vu&LcYZ_gh@&ps&X=u<#aN`?j*&P?J_8%fIZ$@z=DaA=RbM{te!jL+=Dl;G1%g$KE~pQ6r@nO-}&RCWL&t28XMpW2u>|c_cTsgY7>X2h%^48 zsz4*b59`}`K_|vXF?>*7KX+zDE2!SnD<|DG^~*1;pFT2rEXu~<4>w24)nUn(AGilW zGzy87>Y(%i(S^;PO&Xcs_ShC)vzyz=PU3`WPb<0|kx6!PV+TC_p)qK%c*bxd1fYkM z&4aEuavnmU%|TK3#XGHUak5^YI|aSO>}qCHLPEj93Dbh1A_$Ui+X*V@wzGAD<~&~kv| z2d1|7*siy1d`U8<66DvTOdTQB*~5lR?+@=5bi##f)+(t0OZk~2?-(p*9cKu(7XUSl zUUIaV=#(~Yxqdg6(GheUlOY-|umI5g&-@%E%0UM;axJ5@p9nIl!(?|48wQ zfFw_9s8ia&)PD!3$PT!vC<;lTWCw-uX&45LTGRicSU*W-0&qA43j9-gxDll771{r< z)EIIoD6{~?=Bc(~(nsz~Z!~(|x|&LMW6jrzc*GiSN#_dQ$Bm5i*MUTq%7h9Q%I?$_ zGnRlmmL15%!^4A3&YhHJ;z=dhav%!NI{Z%iN;81g6C}!%=FDE=*I3jBu3R8H?fK^U zZOXeb8N+gb59)#tz90nR9)`mO32*eE8q9eJ#<397;C6jtJ`t23%-+}c>z>sB%v5EX zl(7j~*;?YmKgyPt^ypft{AaGNweIeo6Knf&`ovODgr$jO9i3(;q4$b!GI)L1$Yl9y z4wgFb{-`S<^p*4S@?j1CSf|6)dmR!gQAJhd?&)bUs5TCYG^9|pVjZ1V-D1Nl!Q89A zL2N7JQ%Fwz7+QQFB?9Q292{A(KWhH_M!Fc3wi-#G>k5JiZaV#_A`}z;2$W^jMSf-? zjR=z1nlu`YW2EjTHlW-%z$FPqWuPy9>(nQ4K~Jmns>>!RS2XRu6~mxnzXF5mvIil2 z!=3ac4ByhNAC}1kGXF?Us38hyJnUH_QzoTnjy3W$$z7oLwZ!gOhOiH+J~sMsL;{G> ztTs=c#59JH6m!zMh(KST03Fc4;2ga-3C_DGv=h5vhLc{025@XBByM~YDJ4jd^LD#g zsC?5A13CsOw@Lh*Evw8R=K%wK{>x31-hy~)I-;NgbM%EG=mrzb(GF4dRhHM+@Cyp8 z|7REJebTrzlEF(g%|EaI3W-1p-GLKr`mEFfhzKj^8&MDZWL1&~Bd7a5##Y1jHpVT> z-15x!cKQHAERsKAf?2k->62XYk$mrL;!aH#^NhzQDS^0Kc!S>AO zu}+N2#8?kI+G{nwqpL3&0bJx6M`Oj_D45%yK^igYFX({IA8H4zXXIAX_Rc5xaeDY! z7hfr<>0w8hTd=-hm!Iu{21j+}{{m*O8z7dnHexpnhXRfCcsnm=`?k&>(Kp(}&w3_Y zgtK=)K*I8yiplg)!txUVgt3=evgYACXQZ9*wUnYeNzw@uoGGHZ_Cuz*#UC6E3q`lI zPM{ZMBOfk#j}q2H5V2zgYY=IC=x1CMI3daAeUJOv%u~Q72b^j0DK`9kd~<))Z2I>y zZcMjJ4(g7HFGhoj8((^Zq<7>%o_|W6dNDp43OgoQl5o&_kdin`Adx?W!~TSoV^a&0 z4v#JMLEbcX(dX-)_4Mte<|M~kZAIua^fM=ka3HJhE$bjD`sK?^D=*S0<0&2K3QEf-Q_Vx>(^sKx~*?VYF)sE3*;d`+YsaurrLqaFld zz?)&$%{9hNyRQ6MK>qym*wjDxteck(?$gTwGjCEYBnIWP^|fxR>cZ(>p-9GY3%rfxLhak$P)OvUG{;yHAUXH9|k_ zkJ~jimC&6OIO)&m#-59+H{7w@go)^v@9Sez*& z7TbF9kkZzOz?Z~!h3ePUTHio*7GkKs4pThZKG5u{1K8)dy%Aep`vmQt0hd$>7*VHt zWX%-ri>5NE1J0AVVZ)6*NG>H%M?UjVL@r6I%f5JVShblz8Ct<&aMr(BXA?-4ff}tH z-FkX&pDl644@!PI@jzi7V7_i)VS)ZH!nWKI31@NA(V8nm-bfLR0#hi+JgCAI&v6ya$pDdH{M4+PF^+4&?u0VXYD{4&C>#?Bsb!)@U7a!N>9 zRej?^^?BXj)UO6NU6}8(aFc~Z6D!x~!FM1nDT0@p`y^(vX+kkaxsKHS+dP-=S?Ot6 zgN*`f!)isE;HW;n!#-j|w-Cc_lB6eHC|U{Z6zu^Yu{$L#Ikf4ff`UvK`WeK0z`=JN zo8RH)f6vmkW(r`sE(8ZCcCeg9bYdbiKKhjIEC#2N3I#YwShu{gs^CWfCM1qDJ=$uZ zItRr15Y#X@WE6p`JWzMsDPb#Q9)uL3>|_))HipXqL}~`hPY1{nx0|vjNHWDVJ#xa& z>iFtv4>(?wR2E=cbRJ#;-`}6sTAt*QS2JH4^{n&w672(A1=2NN`;GnKdgZe1W5XvZ zhGsH5Z&aHofjWoQLYgB^KHT+}?ege_<>kn{cblo6KBE{PmLAlCm)jSLrD+(o1yg4f z^E`%7JbYetZH_uqAi#|z%azEMXk#kxnf5sg9x!x&ECvr@JthL`Khau{d;JkxkPh9Q zv)vvS4Id<8`m!&|Xw@PWl12#nJiT^a69#Yas81OBxZkf6gX|zL;0&XTkUu^Ek`W;d zK*aS^@7;sH>mR*L>8FT+dez)z?ofDrV_xf8Akgm=B`TQIi67ouobuk}HW4^XLT4Qe zo#6jivi%D42T2G*%fjd{jMQ3yF0?PV5*!3U5{E}YWdH<#>vcNl2&Nx5ih4I(&H>nH zxwrdwHKN6_pnMzOWl!1I{SpNLLW)p)*iyd-%+0yZ?mm8C16Z}0Hw>I~zVBG&%Hw3V zf?;Y(UO0g$6`4ssuk$Tj*Lnom&SJji#{R8v_dVIU7TC(U=jtr6O3Z`O<|sXxcD4#x zFzp2^5ixLZ{>foe4Tm;JN?Ga>RTMZsY|XmeE>1`75>N*oVT?#+g#JcDkL)Qb#$KE4 z@XpvVHI3|NK?ax=}FTbs5t$21*t61`RHHGD@0nA(5hYR<+Y$xZCz2E1H52(lJ&0v|&ew;(fU z64V;I3~v3Rag-t=AAkI7SE7+E!%ez5X%jG-{189l{gymNi)Fq(7TDxEBWMV>HslUv zs#t4$?pntJ%u%y}mO#_~&To1F{#QL}pM}G@X74|$RvXDRbRdIU+h!`fvKCxA%yIwi zW!|s=4mvVGWh_lf|JYBvVvemVBQ>@Bdyoetnp_?KFsbybk}6$8OqE?{U<&c1(OXi# z5&zo%?L_+?`K~6L*NyXP(Vdy=;Yi-qCT^qrE)Oce2xbh^W9z*MdN;rW!0(CnAD&LL zmyoR#R~%_(Un7qXJReG~5)IZ0x|PKNZNZ`99h2?^@jl1{;*psvSLs-8VsU$WZrzml zYKbI{XtO9d^vTNhjc6>FvE16&D6CstXr)gCD*$NnH`~V3r*#*U-+?p|&`9ccTjl2t zJfG)W(We{xQl!hON3#6+j@(_-WQ)}RPT>J9u5GWxhlCdDdl8rDXydkP70$a!O*=b# ztCg;Y1FmH(?QAI_oRBUA(EOhN;YRVb?S$7GN{Z>KW^csa5%`||G8jXY* zH0u*wMT|MxoeA!6k9M-B$G6YGBqRi((NqT_tFIv#-!ZS%7+jK0kFBP%eM#ZC1HUrB zs0MtPw$jt5gbn^{F!vG$v)l9I#}Hh%lJS1?27uJd8~IXz;$X0>by7}o05)G^1x~%2 zaL-Q$M<=)(eU@Zkr;q(kQ@Nf2zz=}6(m!6$3`5ucH9Ykimge@&Wg9=w>4=iw;aUfu zMc;ZcGyLs)LonTLDcJjS!QPLQZsM!TBV#_1U;OGzim!EiS{(yRD(*{^HmRyFGr!R#IDUUpQKWUm1TQM3)U81(&F( zU^1oSkyb|+BA~*G{Lir?eKyzUb3(O-sHm7yoaW}2yp?g*`W=^LE0QVCGK|>q+3-Go zoX3;?*vdDjucLOHAk4er$z=3oeDAQ+V=9m*97B-)o2^dY-javJi*rkTp+VE5oEtZj@PQv)5PfRduYJ9zkYMNde!J=_{dAKrF&O#XJNsRn zD?p7JH4$3sf?o~azc=U_8)LH_aIUCZc`%ao@EUmkCF6Mc4?6+gsM&Yw&;Xg8ut+k( zG&g__4Kj@~eJ=ZUph&_}LhcD*8up$EEr)vF0>lEGc=u-E&HT4wgzO;miM@04OeSRv z<<`eV_DWWR@sQXt*yXo*18~qYvNTjh+U?KJ@!_WX-r=SZMa!Lh zXnW~-Tu8ZrcYWF@Zd=ixoKDYejF_6Lvf(6HX*m4d%XqvBoXU~(i{Bwrfq~FG@Hb+v z&#B=|l_?H6L>BS#Ra$-hw~Q!iM8q5u6EJS)T_iM?fQyDm2zr9PL&MH3OAd>57$%8Q zm9SI&Sns3q6&|O4<5p_CWTmjb&E)Crr*wHQp3sehR5wz1LjPO@D&U#L@DXh~kp zog;?s1PwXufOGAWrnro{GGi}Rjq+pjt!jySwwi+)M?gm&kPvB^k1vY@4BTx@?3^+T z-{DVP^ieJ+cjuZXFN+U;dfT%*@4E*tC<24+{r^|eb;ncv{eRqxdu3cR+qI$_Av^1m z?Sm_X5Rr_KE9#QHx0@Yh&nqJ&BrCZ^MpR~8D=V4V@jHHBe|X%-oBMtr*Ez5Gd_G?) zOsS=U(V)zFkNC#{6AJCjHnzaJE)Y*9!;JwyI-(GkZEY<&cDrK(v^8Y4(h(4oTo-V- zK(00LtFYha8>pxtC~T8!L8+v_N*uJ}=ur)$Z#Q#Fj8oY&JI1~`s_VD3yo*UrbjBTd z0WOJFi4p+j74W^&Ha57}?*D6aOeV43$U3I~J_xl@l?-*ei5Cy&){Xh;y*dds7CU9_ zt)E+;?+lqGPERA=(7ibbSJ%FOzrLzC<_E+O4_hpGs<1{}+U!a-(BsGoBcMRj5SXZ~ zUZtA)?e{fE6QEOZ93jX^SamyJa%ol0!RkK=q#oLGcz)j$__2a%#Nf%6;t+tA5kSxD z>6KoPr8uq)RFR5}eLZCDst>OyS_!VK)71yfUk8$YI@vic0M#pD5lrrh);9x~hV%Ot zlxp`rUZ=>(=i>*=WwF42THbX!(f~CiXDEoEIajoAgB&+)zPJD!$=BftS`Du{c#3Rn zi4L_IUNj~)zO3>!-ATwruSz7;XBk1of;0j6Y;$TzE#x&&FV4Heb6pX|TkEO<%g=M&=_Q(Dyd+&b$#p$$2X;CZF2Fq8F^n6NZ){ndN_ofFUj@$Q+5Hqv`2mjN*u+6ZDrzxA@)B@?)vC<#Jq|f~rFu z_s6V!`i*g?&zx%~J*K?R)>}_@FW`mHk5M~5AnO>y>O;`3)ue=~y z6*Mz|kJ2cEGj@=7yCTUcH`hq><)U8xFTXrj%8STSnDz_gXzKj4bzZ=fP<@luJhD^^ zfIMur@3W!^*JFmkN7Z%RheB?%v}br^9PSaq1+HB!3}=XmJm@BGke9i^Ff$Y)ME743 z%_<3E6Jik>0uSoAfRn|a1eU^8EK%}+KKDyc(vi&Q5B zGcdZ8=-A4MBmaSy*$4QcwZq=`%dkol^)B zr4Fv(z<>fHUy8Nny2 zII@E6C(lDnAtE!9iux41bjoN=5tfxu&GSbrh-!u6BIkv4o`)DfF6z8l`!8E9(fDka z5wtJhe#|)E@ydndJ`g=+NP7D40#1 z29kyoIXRsrAvy(osSlfEyg-$!816~gN)sq_mQ{#up!muyd>CaIey@#RQ6J{zN}AJ@ zqni^V&trfhs=^TXFY*8fOMZv0_2gKFj!7u%(#xtU66ie40vU7jgS`ALTLKMABoARf za=>6>epv&P~{E_e! z_8(Ich;C=o-`Xv%h@8>Qfe8g0H^Her<>yBO4uYCC3_*c8umhAsnbR6(3Nu!-Qw!IV zzB5|W?Yz1IdTNqx+o_J~h$?DX`VxW}y6CBc2n`+1~L zg}v^nt7fIUt?j2nFsls=Ce-#Eu>38j)N_^a|Cm?^rIXZG&!@;O4uf)piqPa=6;R|`m zWd0w9;7y(BEH`T3Txbbp?{HeOJI&OC(^C#4hQdVBd)i+Fs6yDZZ$v=^QqE*9t5bk+ zBY6q=L`l)nHTza(GYRD3k_ebnmVHSSf;J)h+RD?Q5M*S|e)e5}v<@^xVhGV&JN_=l?z2)1X27z#bhRQu_`jp?(RHr%JsP*2mR zM*hEoRB7JOz!%SqTyZQ2Bn+$Sd@!0H05Uo%JBVPHnsrEhg@6NNqP98^ndBVwtq|1s zkWb>cDZn^9m?)2yB*9ek2KPsy3OT4|#paWvNIOPa=<}oZB4Yrl$_^1Y zF*H+W#USFZ3j|y?>y*ByCEdK1^t8!yQ*xrwGup|DC5gS`^!+=2`$zPSXjU=sdnY68 z5Q4qcH%6eKBWpu`ni(1iIXJ3a)AOG#$=iNnLdjTHSNFQR5NKcG1n3FKF10VB{34&e ztkgHPoFP*jj1mY0H|0UFGG8;jxcm1RX{aiyEBJqPqggc%ZdQb8Xlq}Z^~%Z~k^R== zrp~Ilc^E)v3jW$_wZ_2-Qr&Y>pejsFKx*)q5AX*Vl^4+v0GUa0|IPTqy~WKAQ--=% zE{Z+A>Jja_={qqPV^%l1B4TpElRL)BgN~hbT3_sx^M-j!xGO}dCkvBMINnAc()WvY zzk2(s?``jxW~l_z!$qhX4OPqs1pogT=ig@iEqmtF+Rh$D(Ve1<&z3n#+YdQoCvL-_ z|6853nY!4~(mt_HEbd25&yF&Nl2MXMEFL2nQ3%@Wl2j2AF~}Y-^BMBp-Zd=+76IWG zVKE`F@-Wzv38guLpPhyu-Q{aCIPXpYHNBy{Gh|v^R#xu>>c&&@8LM^7cnYXTtr)ne zF1qG~g2tb1NTv+VkvMF^qDe+cX{H`wFB*XqV#0#ss>jr)p@}gEuM}^HU0_r<|JtN8 znwvQy(Jo==?fp6KegOd)f>O<^xl7{}g;Gq+8EOs`Nda;Pp(ZzOO0o#3h<9oA16uW< zYEyMzhKKdoyI=`(*|HAN^~om!N>_5Yv=g)sG$awlzI{J_E7da0w;;O|69CBTS#E~5 zXKE>sIKMbqcX`~T3v_Q4{I;Rx4%8Gj(|^7FZO7w5(ePP=%b~#09xC7Er<gOt##&9o{WFnc>`R4Pl4yT@l%k=813E~}eX_L4NBZ4ffTpjZ zY`4nQ{&xvezk6ONfXTV5ylgYAb*6Q}oL%Pzx36*G zPSmkPw=J-lQio*ng(|N7df=F~Wmn@Et2M(2u{`d)4WL7BlUfo1jg;Q5xt!8DXNUOY z`R1peFT|933;p6bu94gZB;9Je9k$~3Ib>(4+z6GOb>+@!_^|+w1Kr%Sy&WI7$Zr@_aym+|Xr3?KdQm`# zfqk58lssu%s~EG;Zs&&_eld!#r4}1MLsj7i z@{FJ3B!hqOv0F-p6jv!3oJ;pKdZZSEn?2pzxZBKGbFmO+$l+U3O%5odwIMqeXdHlJco>N6?%80Es!OXjX9a9cYSk( zywQE8*ZR?PArOa{mA4suH{$$Nx`x{PyE(VY<1}Cq*d3dW8)J7@rMva=$ZLia^$Cj!WkL^&|hMo`7C>Jl<;{jC5}s%E8K>Y2dLUX zoJKzRvzey^?S5l${ZV|m&!UEOjzX-S{4?h~6G-kzTYshy-B}d9U3oFM6R>>x$G*O0 z(u>FQ>Mi|!a$oY{51YpIna_r!$^0xdQf_nXxrYO(?x<5TW7-&u4yyxi5pk;fVbC^H zqsPu^uP|*hmR;>^Yw%$G)ykA)083&$XKHHthnz<33M<%Y5x%z*tnxqbDQSE1!o8(PIcq{eB^SS-wf_Ve78i zJ?(nSdMuq|yHry2pFsS}XjKQyESgh`^R=(@B-ux*&Ee@Z?RX6Pd8ovv^p#IWnL}%Q56|Nm!wg~@`*O& z+~OnH^a%Il2MP>`1431n^(koNr-fra!3vx;Tz*C+BRd=QsrJxkgM8Yq8EP&pEF5{A zpIvqLx<)6Wda2H1>9Ou>qtxVF0Mz=m_#`Sz_z$qgO9A{4PQS(*mV> z*l*r6B`1gci?-3yF7iokjec9%(chY`; zX4(f=QqAo@$Xd{qSb3TzZ~`PQJul*QXWhABw+InptX`ES17_5!?LK8u4Ug7ZMwM>% z_7qD3=ju3S$BIrsWBl2Ta!w38ekKoy;(+~)oudb~eMy&{ijGS^`p3Fn_R$Hm*>|%W z9aM}kwBfodLR2XLHu{L4KJqXSv`jwiD90Jd&tJ#F#$M>KGGWFlLlSmr0Y|*QVio0; zKiSdOJU4tr!Es>Ms+$>`q7jOG{`|R6p!WeHcOK0?ouv}49%=D)uJD)8x#c0|zWh?L z?TF_LNxgb#v3m)a><^3470S2Za>%g3r3Yga!1U$YlL>?|C%-Ph3BH|CNGi5`m65&{ zkC_jJl{-YcS93^084KoIgnLA1zrbE9J-+06IKkTF8FoRxgA^1Fi_`$Fp_i_5YYq#B zHdFQ0u}=iU8l6nBubAdJyb5Zc@IPySl_(j2X@KP9nhMEVwZr0o!mU3X_olMEx`K*2 zilI5lMF!$XDoq2FAPnQNF zLhmcT4UBmp&6U2w2j_d-##+826_u%X&q+5yjuRZkd{z($TCu^BKN5qHwSx z65zP{kNad7*=dh3|JdlxqJ?<;XBwV6W2uYS5ZoR z`P^`LqJK^C@rlA%27Bgofr~x{6tr)$$Z3 zz1gzC(}>?++APjU=i6{1{9e}dsW>=FG_zp@f`lFInBxFxArC+ zu^3J9uO#IVN9sNblTh9H7I%!j>mKP&+-#wIi=uM4Yb96Um4%js3FOCteP}7BItpA- zOg`b2&AYhbpU01j2sT(NUS`10QQ<5hE~;2cIbZg;>Ke}c1b0N7`S{lc^GVm3SSOB3 zx;3nz#HGXzWyCCU%K?EfE+W=tv_sYe%8W}&63WE$b5sx< zq&9q0klk_2tPU>E28p2a%dO z8Sy#!zq=o&oB}Kx5*w=~5FQg*PlA+E_o^mmyLqm*uhQH({ppjyN%Qn?$&Jaq{E*OH z?L=KYcxqa9wzi}=tc>nZ#eZiazGm~&dxlhwe(2!2BNmfO1S3Rwo-lwPG8=dMktP}D z{I8Y~Dx3Tk5`jQ}^*eudiavu|*z(^9!61;g^jwtUX>flaJi6D@-|0eqI%k$0@bA#uK9#rqQ{Zn*>n*O#;TE4p{D}_COyo+`k zPQd8vFW+yxDu!jPS8cvKBY|OX)cL95FVou%Zb(N21G;#q^o_b9b5XOQ%jbbJmC zRo>tz+A^S8&-1DjvB2e@+lwX$>`HtF_PAI{adSl-obE; z$Bw#=sFKPI?Bsl762t|EVR#}Mbam4XuXGsH+O zukGd+XWoZp>V{YfE#8yA^h-fZ;`V^^o4in1@GbUR)mI$$+f+ag^F`B#XK{iNVd{@r zH|$Tsna5hI*hT&z9yxS7NP$Xse_-my(w;RDyRp8HAFWc7BF@e_^E&`bEFs?RV6}2bNpc6RJ%Ds?b7`?|+LAd_$*|s+Zl0n%M z;`qre!vORW$6_6EQq)iwv}313)c1eyY`Q9H2OC3DBS6cy&^-= zC?Qr~3<>SP@>_h-lXbF9Tf76r*8Fn37!B83H706ohY; za+23*s=DwP5QBX{kRI}P&1gon=fKWb!1BNwfVTkoYR%nx;C Date: Thu, 22 Feb 2024 10:27:35 -0800 Subject: [PATCH 56/64] test: Fix several test failures (#6281) - Fix bogus assertion failure in tests on Safari (#6272) - This test should not be seeking so close to the duration (10ms) as to cause flakiness on certain browsers. Adjusting the seek time fixes the assertion without compromising the purpose of the test. - Fix uncaught rejections in load graph tests (#6274) - These tests had calls that were interrupted by the teardown process that occurs after the test body. Waiting for the operations before ending the test fixes the issue. - Fix interrupted load in test on Tizen (#6274) - This test triggers a deliberate DRM error without waiting for load(). On most platforms in the lab, the load() operation completed before the error. Not so on Tizen. This exposed a general problem in which we should be catching errors in this test. Only timing saved us on most platforms. Closes #6272 Closes #6274 --- test/player_integration.js | 10 +++++++++- test/player_load_graph_integration.js | 23 +++++++++++++---------- test/player_src_equals_integration.js | 4 ++-- 3 files changed, 24 insertions(+), 13 deletions(-) diff --git a/test/player_integration.js b/test/player_integration.js index 7c8c9aa902..84956b0cc7 100644 --- a/test/player_integration.js +++ b/test/player_integration.js @@ -1208,13 +1208,21 @@ describe('Player', () => { 'com.widevine.alpha': bogusUrl, 'com.microsoft.playready': bogusUrl, }); - await player.load('test:sintel-enc_compiled'); + + // This load may be interrupted, so ignore errors and don't wait. + const loadPromise = + player.load('test:sintel-enc_compiled').catch(() => {}); await errorPromise; expect(unloadPromise).not.toBeNull(); + if (unloadPromise) { await unloadPromise; } + + // This should be done, and errors ignored. But don't leave any Promise + // unresolved. + await loadPromise; }); }); // describe('unloading') diff --git a/test/player_load_graph_integration.js b/test/player_load_graph_integration.js index b8c18208d4..9d3a5e9800 100644 --- a/test/player_load_graph_integration.js +++ b/test/player_load_graph_integration.js @@ -378,11 +378,11 @@ describe('Player Load Graph', () => { // Make the two requests one-after-another so that we don't have any idle // time between them. - const attachRequest = player.attach(video); - const loadRequest = player.load('test:sintel'); + const attach = player.attach(video); + const load = player.load('test:sintel'); - await attachRequest; - await expectAsync(loadRequest).toBeRejected(); + await attach; + await expectAsync(load).toBeRejected(); // Wait a couple interrupter cycles to allow the player to enter idle // state. @@ -425,22 +425,23 @@ describe('Player Load Graph', () => { // Normally the player would initialize media source after attaching to // the media element, however since we don't support media source, it // should stop at the attach state. - player.attach(video, /* initMediaSource= */ true); + const attach = player.attach(video, /* initMediaSource= */ true); await shaka.test.Util.delay(/* seconds= */ 0.25); expect(lastStateChange).toBe('attach'); + + await attach; }); it('loading ignores media source path', async () => { await player.attach(video, /* initMediaSource= */ false); - // Normally the player would load content like this with the media source - // path, but since we don't have media source support, it should use the - // src= path. - player.load(SMALL_MP4_CONTENT_URI); + const load = player.load(SMALL_MP4_CONTENT_URI); await shaka.test.Util.delay(/* seconds= */ 0.25); expect(lastStateChange).toBe('src-equals'); + + await load; }); it('unloading ignores init media source flag', async () => { @@ -450,10 +451,12 @@ describe('Player Load Graph', () => { // Normally the player would try to go to the media source state because // we are saying to initialize media source after unloading, but since we // don't have media source, it should stop at the attach state. - player.unload(/* initMediaSource= */ true); + const unload = player.unload(/* initMediaSource= */ true); await shaka.test.Util.delay(/* seconds= */ 0.25); expect(lastStateChange).toBe('unload'); + + await unload; }); }); diff --git a/test/player_src_equals_integration.js b/test/player_src_equals_integration.js index e7c9ff07f6..124562a8a6 100644 --- a/test/player_src_equals_integration.js +++ b/test/player_src_equals_integration.js @@ -115,8 +115,8 @@ describe('Player Src Equals', () => { expect(video.currentTime).toBeLessThan(2.0); // Trigger a seek and then wait for the seek to take effect. - // This seek target is very close to the duration of the video. - video.currentTime = 10; + // This seek target is very close to the duration of the video (10.01s). + video.currentTime = 9.5; await waiter.waitForMovementOrFailOnTimeout(video, /* timeout= */10); // Make sure the playhead is roughly where we expect it to be after From 5a53adf3af0eeb9e4073ba21e54d2b4977a9269e Mon Sep 17 00:00:00 2001 From: Joey Parrish Date: Thu, 22 Feb 2024 10:35:45 -0800 Subject: [PATCH 57/64] test: Restore disabled tests on Edge (#6282) Whatever was wrong seems to be fixed in `main`, so we can restore these tests. Closes #5834 --- test/hls/hls_parser_integration.js | 31 +---------------------- test/transmuxer/transmuxer_integration.js | 31 +---------------------- 2 files changed, 2 insertions(+), 60 deletions(-) diff --git a/test/hls/hls_parser_integration.js b/test/hls/hls_parser_integration.js index aa1967c9b1..5fb472f585 100644 --- a/test/hls/hls_parser_integration.js +++ b/test/hls/hls_parser_integration.js @@ -4,36 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * For unknown reasons, these tests fail in the test labs for Edge on Windows, - * in ways that do not seem to be unrelated to HLS parser. - * Practical testing has not found any sign that playback is actually broken in - * Edge, so these tests are disabled on Edge for the time being. - * TODO(#5834): Remove this filter once the tests are fixed. - * @return {boolean} - */ -function checkNoBrokenEdgeHls() { - const chromeVersion = shaka.util.Platform.chromeVersion(); - if (shaka.util.Platform.isWindows() && shaka.util.Platform.isEdge() && - chromeVersion && chromeVersion <= 122) { - // When the tests fail, it's due to the manifest parser failing to find a - // factory. Attempt to find a factory first, to avoid filtering the tests - // when running in a non-broken Edge environment. - const uri = 'fakeuri.m3u8'; - const mimeType = 'application/x-mpegurl'; - /* eslint-disable no-restricted-syntax */ - try { - shaka.media.ManifestParser.getFactory(uri, mimeType); - return true; - } catch (error) { - return false; - } - /* eslint-enable no-restricted-syntax */ - } - return true; -} - -filterDescribe('HlsParser', checkNoBrokenEdgeHls, () => { +describe('HlsParser', () => { const Util = shaka.test.Util; /** @type {!jasmine.Spy} */ diff --git a/test/transmuxer/transmuxer_integration.js b/test/transmuxer/transmuxer_integration.js index d203dcdc8f..3a9fa501c2 100644 --- a/test/transmuxer/transmuxer_integration.js +++ b/test/transmuxer/transmuxer_integration.js @@ -4,36 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * For unknown reasons, these tests fail in the test labs for Edge on Windows, - * in ways that do not seem to be unrelated to transmuxers. - * Practical testing has not found any sign that playback is actually broken in - * Edge, so these tests are disabled on Edge for the time being. - * TODO(#5834): Remove this filter once the tests are fixed. - * @return {boolean} - */ -function checkNoBrokenEdge() { - const chromeVersion = shaka.util.Platform.chromeVersion(); - if (shaka.util.Platform.isWindows() && shaka.util.Platform.isEdge() && - chromeVersion && chromeVersion <= 122) { - // When the tests fail, it's due to the manifest parser failing to find a - // factory. Attempt to find a factory first, to avoid filtering the tests - // when running in a non-broken Edge environment. - const uri = 'fakeuri.m3u8'; - const mimeType = 'application/x-mpegurl'; - /* eslint-disable no-restricted-syntax */ - try { - shaka.media.ManifestParser.getFactory(uri, mimeType); - return true; - } catch (error) { - return false; - } - /* eslint-enable no-restricted-syntax */ - } - return true; -} - -filterDescribe('Transmuxer Player', checkNoBrokenEdge, () => { +describe('Transmuxer Player', () => { const Util = shaka.test.Util; /** @type {!jasmine.Spy} */ From 250ad33b3e1405ca0a42b2168d9b6527695efeae Mon Sep 17 00:00:00 2001 From: Joey Parrish Date: Thu, 22 Feb 2024 14:11:18 -0800 Subject: [PATCH 58/64] test: Fix missing HLS parser in tests (#6284) A test suite that overwrites the HLS parser needs to restore it afterward. To aid in debugging future parser issues, this adds the detected or specified MIME type to the error object for UNABLE_TO_GUESS_MANIFEST_TYPE. Closes #5834 --- lib/media/manifest_parser.js | 3 ++- lib/util/error.js | 1 + test/player_unit.js | 12 +++++++++--- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/lib/media/manifest_parser.js b/lib/media/manifest_parser.js index 3d5798c02a..b629a9a945 100644 --- a/lib/media/manifest_parser.js +++ b/lib/media/manifest_parser.js @@ -125,7 +125,8 @@ shaka.media.ManifestParser = class { shaka.util.Error.Severity.CRITICAL, shaka.util.Error.Category.MANIFEST, shaka.util.Error.Code.UNABLE_TO_GUESS_MANIFEST_TYPE, - uri); + uri, + mimeType); } diff --git a/lib/util/error.js b/lib/util/error.js index 126fbc7992..16a649be5b 100644 --- a/lib/util/error.js +++ b/lib/util/error.js @@ -527,6 +527,7 @@ shaka.util.Error.Code = { *

  • Configure the server to accept a HEAD request for the manifest. * *
    error.data[0] is the manifest URI. + *
    error.data[1] is the detected or specified MIME type. */ 'UNABLE_TO_GUESS_MANIFEST_TYPE': 4000, diff --git a/test/player_unit.js b/test/player_unit.js index ea4e837762..c89d37a772 100644 --- a/test/player_unit.js +++ b/test/player_unit.js @@ -667,15 +667,21 @@ describe('Player', () => { }); describe('when config.streaming.preferNativeHls is set to true', () => { - beforeEach(() => { + beforeAll(() => { shaka.media.ManifestParser.registerParserByMime( 'application/x-mpegurl', () => new shaka.test.FakeManifestParser(manifest)); }); + afterAll(() => { + // IMPORTANT: restore the ORIGINAL parser. DO NOT just unregister the + // fake! + shaka.media.ManifestParser.registerParserByMime( + 'application/x-mpegurl', + () => new shaka.hls.HlsParser()); + }); + afterEach(() => { - shaka.media.ManifestParser.unregisterParserByMime( - 'application/x-mpegurl'); video.canPlayType.calls.reset(); }); From 852d5ba98da9bc467593fb681f354402d1e6aaa4 Mon Sep 17 00:00:00 2001 From: Joey Parrish Date: Thu, 22 Feb 2024 22:59:28 -0800 Subject: [PATCH 59/64] test: Fix prefetch test fake pollution (#6285) When overwriting any part of the library or platform in a test, we must restore it afterward. This fixes two test suites that overwrote SegmentPrefetch with a test fake, but never restored the original. This fixes failures in unrelated preload tests running in uncompiled mode. Closes #6275 --- test/media/streaming_engine_unit.js | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/test/media/streaming_engine_unit.js b/test/media/streaming_engine_unit.js index cf266c18a9..f2a307be7b 100644 --- a/test/media/streaming_engine_unit.js +++ b/test/media/streaming_engine_unit.js @@ -3996,6 +3996,12 @@ describe('StreamingEngine', () => { } describe('prefetch segments', () => { + let originalPrefetch; + + beforeAll(() => { + originalPrefetch = shaka.media.SegmentPrefetch; + }); + beforeEach(() => { shaka.media.SegmentPrefetch = Util.spyFunc( jasmine.createSpy('SegmentPrefetch') @@ -4013,6 +4019,10 @@ describe('StreamingEngine', () => { streamingEngine.configure(config); }); + afterAll(() => { + shaka.media.SegmentPrefetch = originalPrefetch; + }); + it('should use prefetched segment without fetching again', async () => { streamingEngine.switchVariant(variant); await streamingEngine.start(); @@ -4080,6 +4090,12 @@ describe('StreamingEngine', () => { let altVariant; let segmentPrefetchesCreated; + let originalPrefetch; + + beforeAll(() => { + originalPrefetch = shaka.media.SegmentPrefetch; + }); + beforeEach(() => { segmentPrefetchesCreated = 0; shaka.media.SegmentPrefetch = Util.spyFunc( @@ -4101,6 +4117,10 @@ describe('StreamingEngine', () => { streamingEngine.configure(config); }); + afterAll(() => { + shaka.media.SegmentPrefetch = originalPrefetch; + }); + it('should prefetch all audio variants for the language', async () => { const segmentType = shaka.net.NetworkingEngine.RequestType.SEGMENT; const context = { From 67cd2dd29d1f281f1f4011ec2cd2a88298dfb350 Mon Sep 17 00:00:00 2001 From: Dave Nicholas Date: Fri, 23 Feb 2024 16:55:07 +0000 Subject: [PATCH 60/64] fix(tXml): html unescape node attributes with urls (#6267) To provide feature parity with the `DOMParser.getAttribute` API which would unescape html entities for free this PR unescapes url strings which come from node attributes. In a similar vain to https://github.com/shaka-project/shaka-player/pull/6198 which unescapes child strings. --- docs/tutorials/upgrade.md | 6 ++++-- lib/dash/content_protection.js | 7 +++++-- lib/dash/segment_base.js | 10 ++++++++-- lib/dash/segment_list.js | 4 +++- lib/dash/segment_template.js | 7 +++++-- 5 files changed, 25 insertions(+), 9 deletions(-) diff --git a/docs/tutorials/upgrade.md b/docs/tutorials/upgrade.md index ce17faad09..396b131caf 100644 --- a/docs/tutorials/upgrade.md +++ b/docs/tutorials/upgrade.md @@ -96,8 +96,10 @@ application: - Configuration changes: - `streaming.forceTransmuxTS` has been renamed to `streaming.forceTransmux` (deprecated in v4.3.0) - - `manifest.dash.manifestPreprocessor` callback now receives a type of `shaka.externs.xml.Node` instead of `Element`. - - `manifest.mss.manifestPreprocessor` callback now receives a type of `shaka.externs.xml.Node` instead of `Element`. + - Callbacks that used to accept `Element` now accept `shaka.externs.xml.Node`: + (`manifest.dash.manifestPreprocessor` and `manifest.mss.manifestPreprocessor`). + `getAttribute()` and `textContent` results must now be decoded if they might contain + escape sequences. You can use `shaka.util.StringUtils.htmlUnescape` for this purpose. - `streaming.useNativeHlsOnSafari` has removed. Now we have another config to do the same for FairPlay `streaming.useNativeHlsForFairPlay` or for HLS (any browser) `streaming.preferNativeHls`. - Plugin changes: diff --git a/lib/dash/content_protection.js b/lib/dash/content_protection.js index a63f30597d..38be75da7f 100644 --- a/lib/dash/content_protection.js +++ b/lib/dash/content_protection.js @@ -191,6 +191,7 @@ shaka.dash.ContentProtection = class { * @return {string} */ static getWidevineLicenseUrl(element) { + const StringUtils = shaka.util.StringUtils; const dashIfLaurlNode = shaka.util.TXml.findChildNS( element.node, shaka.dash.ContentProtection.DashIfNamespaceUri_, 'Laurl', @@ -204,7 +205,8 @@ shaka.dash.ContentProtection = class { const mslaurlNode = shaka.util.TXml.findChildNS( element.node, 'urn:microsoft', 'laurl'); if (mslaurlNode) { - return mslaurlNode.attributes['licenseUrl'] || ''; + return StringUtils.htmlUnescape( + mslaurlNode.attributes['licenseUrl']) || ''; } return ''; } @@ -642,7 +644,8 @@ shaka.dash.ContentProtection = class { } const ivHex = cryptoPeriod.attributes['IV']; - const keyUri = cryptoPeriod.attributes['keyUriTemplate']; + const keyUri = shaka.util.StringUtils.htmlUnescape( + cryptoPeriod.attributes['keyUriTemplate']); if (!ivHex || !keyUri) { throw new shaka.util.Error( shaka.util.Error.Severity.CRITICAL, diff --git a/lib/dash/segment_base.js b/lib/dash/segment_base.js index eaee5006af..ed31002f52 100644 --- a/lib/dash/segment_base.js +++ b/lib/dash/segment_base.js @@ -16,6 +16,7 @@ goog.require('shaka.media.WebmSegmentIndexParser'); goog.require('shaka.util.Error'); goog.require('shaka.util.ManifestParserUtils'); goog.require('shaka.util.ObjectUtils'); +goog.require('shaka.util.StringUtils'); goog.require('shaka.util.TXml'); goog.requireType('shaka.dash.DashParser'); goog.requireType('shaka.media.PresentationTimeline'); @@ -39,6 +40,7 @@ shaka.dash.SegmentBase = class { const MpdUtils = shaka.dash.MpdUtils; const TXml = shaka.util.TXml; const ManifestParserUtils = shaka.util.ManifestParserUtils; + const StringUtils = shaka.util.StringUtils; const initialization = MpdUtils.inheritChild(context, callback, 'Initialization'); @@ -49,7 +51,9 @@ shaka.dash.SegmentBase = class { let resolvedUris = context.representation.getBaseUris(); const uri = initialization.attributes['sourceURL']; if (uri) { - resolvedUris = ManifestParserUtils.resolveUris(resolvedUris, [uri]); + resolvedUris = ManifestParserUtils.resolveUris(resolvedUris, [ + StringUtils.htmlUnescape(uri), + ]); } let startByte = 0; @@ -244,13 +248,15 @@ shaka.dash.SegmentBase = class { const ManifestParserUtils = shaka.util.ManifestParserUtils; const MpdUtils = shaka.dash.MpdUtils; const SegmentBase = shaka.dash.SegmentBase; + const StringUtils = shaka.util.StringUtils; const representationIndex = MpdUtils.inheritChild( context, SegmentBase.fromInheritance_, 'RepresentationIndex'); let indexUris = context.representation.getBaseUris(); if (representationIndex) { - const representationUri = representationIndex.attributes['sourceURL']; + const representationUri = + StringUtils.htmlUnescape(representationIndex.attributes['sourceURL']); if (representationUri) { indexUris = ManifestParserUtils.resolveUris( indexUris, [representationUri]); diff --git a/lib/dash/segment_list.js b/lib/dash/segment_list.js index 7a4dbcfa52..42bf753e62 100644 --- a/lib/dash/segment_list.js +++ b/lib/dash/segment_list.js @@ -16,6 +16,7 @@ goog.require('shaka.media.SegmentReference'); goog.require('shaka.util.Error'); goog.require('shaka.util.Functional'); goog.require('shaka.util.ManifestParserUtils'); +goog.require('shaka.util.StringUtils'); goog.require('shaka.util.TXml'); goog.requireType('shaka.dash.DashParser'); goog.requireType('shaka.media.PresentationTimeline'); @@ -290,6 +291,7 @@ shaka.dash.SegmentList = class { ].filter(Functional.isNotNull); const TXml = shaka.util.TXml; + const StringUtils = shaka.util.StringUtils; // Search each SegmentList for one with at least one SegmentURL element, // select the first one, and convert each SegmentURL element to a tuple. return segmentLists @@ -305,7 +307,7 @@ shaka.dash.SegmentList = class { 'attribute or SegmentTimeline, which must be accurate.'); } - const uri = urlNode.attributes['media']; + const uri = StringUtils.htmlUnescape(urlNode.attributes['media']); const range = TXml.parseAttr( urlNode, 'mediaRange', TXml.parseRange, {start: 0, end: null}); diff --git a/lib/dash/segment_template.js b/lib/dash/segment_template.js index 57fc09b0d2..0fa70c368e 100644 --- a/lib/dash/segment_template.js +++ b/lib/dash/segment_template.js @@ -17,6 +17,7 @@ goog.require('shaka.util.Error'); goog.require('shaka.util.IReleasable'); goog.require('shaka.util.ManifestParserUtils'); goog.require('shaka.util.ObjectUtils'); +goog.require('shaka.util.StringUtils'); goog.requireType('shaka.dash.DashParser'); goog.requireType('shaka.media.PresentationTimeline'); @@ -195,6 +196,7 @@ shaka.dash.SegmentTemplate = class { static parseSegmentTemplateInfo_(context) { const SegmentTemplate = shaka.dash.SegmentTemplate; const MpdUtils = shaka.dash.MpdUtils; + const StringUtils = shaka.util.StringUtils; const segmentInfo = MpdUtils.parseSegmentInfo(context, SegmentTemplate.fromInheritance_); @@ -211,7 +213,7 @@ shaka.dash.SegmentTemplate = class { unscaledPresentationTimeOffset: segmentInfo.unscaledPresentationTimeOffset, timeline: segmentInfo.timeline, - mediaTemplate: media, + mediaTemplate: media && StringUtils.htmlUnescape(media), indexTemplate: index, }; } @@ -534,11 +536,12 @@ shaka.dash.SegmentTemplate = class { const ManifestParserUtils = shaka.util.ManifestParserUtils; const SegmentTemplate = shaka.dash.SegmentTemplate; - const initialization = MpdUtils.inheritAttribute( + let initialization = MpdUtils.inheritAttribute( context, SegmentTemplate.fromInheritance_, 'initialization'); if (!initialization) { return null; } + initialization = shaka.util.StringUtils.htmlUnescape(initialization); const repId = context.representation.id; const bandwidth = context.bandwidth || null; From 6bd9f42cf2885430fd72ba11cfa3026d848ea8be Mon Sep 17 00:00:00 2001 From: Joey Parrish Date: Fri, 23 Feb 2024 11:02:03 -0800 Subject: [PATCH 61/64] chore: Fix deprecation messages (#6289) Some deprecation messages were misleading, and claimed that entire classes like AbrManager were deprected, when in fact, it was a particular form of AbrManager (without a method) that is deprecated. This adds method and other details to the deprecation calls where needed. We also had a malformed messsage where join('') was called on the pieces instead of join(' '). This fixes the formatting. --- lib/ads/ad_manager.js | 2 +- lib/deprecate/deprecate.js | 2 +- lib/media/manifest_parser.js | 2 +- lib/player.js | 8 ++++---- lib/util/ts_parser.js | 4 ++-- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/ads/ad_manager.js b/lib/ads/ad_manager.js index 732f00ea84..55590e252e 100644 --- a/lib/ads/ad_manager.js +++ b/lib/ads/ad_manager.js @@ -656,7 +656,7 @@ shaka.ads.AdManager = class extends shaka.util.FakeEventTarget { */ getServerSideCuePoints() { shaka.Deprecate.deprecateFeature(5, - 'AdManager', + 'AdManager.getServerSideCuePoints', 'Please use getCuePoints function.'); return this.getCuePoints(); } diff --git a/lib/deprecate/deprecate.js b/lib/deprecate/deprecate.js index 1d6912c99d..ee58d75aed 100644 --- a/lib/deprecate/deprecate.js +++ b/lib/deprecate/deprecate.js @@ -107,7 +107,7 @@ shaka.Deprecate = class { libraryVersion, '. Additional information:', description, - ].join(''); + ].join(' '); shaka.log.alwaysError(errorMessage); goog.asserts.assert(false, errorMessage); diff --git a/lib/media/manifest_parser.js b/lib/media/manifest_parser.js index b629a9a945..80a5a4c339 100644 --- a/lib/media/manifest_parser.js +++ b/lib/media/manifest_parser.js @@ -28,7 +28,7 @@ shaka.media.ManifestParser = class { */ static registerParserByExtension(extension, parserFactory) { shaka.Deprecate.deprecateFeature(5, - 'ManifestParser', + 'ManifestParser.registerParserByExtension', 'Please use an ManifestParser with registerParserByMime function.'); } diff --git a/lib/player.js b/lib/player.js index 8be4517d09..ee49d65959 100644 --- a/lib/player.js +++ b/lib/player.js @@ -752,7 +752,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget { // player having been initialized. if (mediaElement) { shaka.Deprecate.deprecateFeature(5, - 'Player', + 'Player w/ mediaElement', 'Please migrate from initializing Player with a mediaElement; ' + 'use the attach method instead.'); this.attach(mediaElement, /* initializeMediaSource= */ true); @@ -1532,19 +1532,19 @@ shaka.Player = class extends shaka.util.FakeEventTarget { this.abrManagerFactory_ = preloadManager.getAbrManagerFactory(); if (typeof this.abrManager_.setMediaElement != 'function') { shaka.Deprecate.deprecateFeature(5, - 'AbrManager', + 'AbrManager w/o setMediaElement', 'Please use an AbrManager with setMediaElement function.'); this.abrManager_.setMediaElement = () => {}; } if (typeof this.abrManager_.setCmsdManager != 'function') { shaka.Deprecate.deprecateFeature(5, - 'AbrManager', + 'AbrManager w/o setCmsdManager', 'Please use an AbrManager with setCmsdManager function.'); this.abrManager_.setCmsdManager = () => {}; } if (typeof this.abrManager_.trySuggestStreams != 'function') { shaka.Deprecate.deprecateFeature(5, - 'AbrManager', + 'AbrManager w/o trySuggestStreams', 'Please use an AbrManager with trySuggestStreams function.'); this.abrManager_.trySuggestStreams = () => {}; } diff --git a/lib/util/ts_parser.js b/lib/util/ts_parser.js index ec38a8fd0b..7b69b8aa62 100644 --- a/lib/util/ts_parser.js +++ b/lib/util/ts_parser.js @@ -433,7 +433,7 @@ shaka.util.TsParser = class { */ parseAvcNalus(pes, nextPes) { shaka.Deprecate.deprecateFeature(5, - 'TsParser', + 'TsParser.parseAvcNalus', 'Please use parseNalus function instead.'); return this.parseNalus(pes); } @@ -769,7 +769,7 @@ shaka.util.TsParser = class { */ getVideoResolution() { shaka.Deprecate.deprecateFeature(5, - 'TsParser', + 'TsParser.getVideoResolution', 'Please use getVideoInfo function instead.'); const videoInfo = this.getVideoInfo(); return { From b88303dd42c92480af1b3d4e674baa2cbf62cf8a Mon Sep 17 00:00:00 2001 From: Joey Parrish Date: Fri, 23 Feb 2024 15:10:43 -0800 Subject: [PATCH 62/64] test: Extend Transmuxer test contents to fix flake (#6291) Some transmuxer tests were flaking on Tizen because the "ended" attribute on the video element was behaving unreliably. The reason this caused a failure is because we try to play 15s of content when the content is only 10s or 12s long, so only the "ended" attribute was allowing the test to complete. We should not be relying on "ended" in this test, as it has nothing to do with the feature under test. By extending the test contents to at least 20s, we should not have to rely on this any more. Closes #6273 --- test/test/assets/hls-ts-h265/index.m3u8 | 2 ++ test/test/assets/hls-ts-muxed-aac-h265/media.m3u8 | 6 +++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/test/test/assets/hls-ts-h265/index.m3u8 b/test/test/assets/hls-ts-h265/index.m3u8 index ca9ece57c8..97173c3efc 100644 --- a/test/test/assets/hls-ts-h265/index.m3u8 +++ b/test/test/assets/hls-ts-h265/index.m3u8 @@ -4,4 +4,6 @@ #EXT-X-MEDIA-SEQUENCE:0 #EXTINF:12.000000, 0.ts +#EXTINF:12.000000, +0.ts #EXT-X-ENDLIST diff --git a/test/test/assets/hls-ts-muxed-aac-h265/media.m3u8 b/test/test/assets/hls-ts-muxed-aac-h265/media.m3u8 index 3122ee2cf8..aee841ce93 100644 --- a/test/test/assets/hls-ts-muxed-aac-h265/media.m3u8 +++ b/test/test/assets/hls-ts-muxed-aac-h265/media.m3u8 @@ -6,4 +6,8 @@ 0.ts #EXTINF:5.000000, 1.ts -#EXT-X-ENDLIST \ No newline at end of file +#EXTINF:5.000000, +0.ts +#EXTINF:5.000000, +1.ts +#EXT-X-ENDLIST From d0e64d7379d44542562ee6fad0619c0ff533813b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wojciech=20Tyczy=C5=84ski?= Date: Mon, 26 Feb 2024 08:16:05 +0100 Subject: [PATCH 63/64] fix(VTT): fix setting textShadow when multiple CSS classes provided (#6287) --- lib/text/vtt_text_parser.js | 3 ++- test/text/vtt_text_parser_unit.js | 31 +++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/lib/text/vtt_text_parser.js b/lib/text/vtt_text_parser.js index eeff9e496a..0f1140f38c 100644 --- a/lib/text/vtt_text_parser.js +++ b/lib/text/vtt_text_parser.js @@ -661,6 +661,8 @@ shaka.text.VttTextParser = class { refCue.fontFamily, cue.fontFamily); cue.fontSize = VttTextParser.getOrDefault_( refCue.fontSize, cue.fontSize); + cue.textShadow = VttTextParser.getOrDefault_( + refCue.textShadow, cue.textShadow); // Overwrite with new values as unable to determine // if new value is set or not @@ -669,7 +671,6 @@ shaka.text.VttTextParser = class { cue.opacity = refCue.opacity; cue.rubyTag = refCue.rubyTag; cue.textCombineUpright = refCue.textCombineUpright; - cue.textShadow = refCue.textShadow; cue.wrapLine = refCue.wrapLine; } diff --git a/test/text/vtt_text_parser_unit.js b/test/text/vtt_text_parser_unit.js index 18943eca65..93cd8878ac 100644 --- a/test/text/vtt_text_parser_unit.js +++ b/test/text/vtt_text_parser_unit.js @@ -1148,6 +1148,37 @@ describe('VttTextParser', () => { {periodStart: 0, segmentStart: 0, segmentEnd: 0, vttOffset: 0}); }); + it('passes text-shadow when multiple classes included', () => { + verifyHelper( + [ + { + startTime: 20, + endTime: 40, + payload: '', + nestedCues: [ + { + startTime: 20, + endTime: 40, + payload: 'Test', + fontStyle: Cue.fontStyle.ITALIC, + textShadow: 'black 5%', + }, + ], + }, + ], + 'WEBVTT\n\n' + + 'STYLE\n' + + '::cue(.shadow) {\n' + + ' text-shadow: black 5%;\n' + + '}\n' + + '::cue(.italic) {\n' + + ' font-style: italic;\n' + + '}\n\n' + + '00:00:20.000 --> 00:00:40.000\n' + + 'Test', + {periodStart: 0, segmentStart: 0, segmentEnd: 0, vttOffset: 0}); + }); + it('supports karaoke style text', () => { verifyHelper( [ From edbac3622933c041164a42e494c3895c67b6b2dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Velad=20Galv=C3=A1n?= Date: Mon, 26 Feb 2024 10:35:10 +0100 Subject: [PATCH 64/64] fix(HLS): Ban unsupported combinations of SAMPLE-AES encryption (#6295) --- lib/hls/hls_parser.js | 17 ++++++++++++++++- test/hls/hls_parser_unit.js | 28 ++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/lib/hls/hls_parser.js b/lib/hls/hls_parser.js index 90fac0d304..e78fce4bbf 100644 --- a/lib/hls/hls_parser.js +++ b/lib/hls/hls_parser.js @@ -4151,7 +4151,22 @@ shaka.hls.HlsParser = class { * @return {?shaka.extern.DrmInfo} * @private */ - static identityDrmParser_(drmTag) { + static identityDrmParser_(drmTag, mimeType) { + if (mimeType == 'video/mp2t') { + throw new shaka.util.Error( + shaka.util.Error.Severity.CRITICAL, + shaka.util.Error.Category.MANIFEST, + shaka.util.Error.Code.HLS_MSE_ENCRYPTED_MP2T_NOT_SUPPORTED); + } + + if (shaka.util.Platform.isMediaKeysPolyfilled()) { + throw new shaka.util.Error( + shaka.util.Error.Severity.CRITICAL, + shaka.util.Error.Category.MANIFEST, + shaka.util.Error.Code + .HLS_MSE_ENCRYPTED_LEGACY_APPLE_MEDIA_KEYS_NOT_SUPPORTED); + } + const method = drmTag.getRequiredAttrValue('METHOD'); const VALID_METHODS = ['SAMPLE-AES', 'SAMPLE-AES-CTR']; if (!VALID_METHODS.includes(method)) { diff --git a/test/hls/hls_parser_unit.js b/test/hls/hls_parser_unit.js index 90a81da4ca..8047c07381 100644 --- a/test/hls/hls_parser_unit.js +++ b/test/hls/hls_parser_unit.js @@ -4074,6 +4074,34 @@ describe('HlsParser', () => { await verifyError(master, media, error, /* onCreateSegmentIndex= */ true); }); + it('if SAMPLE-AES encryption with MSE and mp2t content', async () => { + const master = [ + '#EXTM3U\n', + '#EXT-X-STREAM-INF:BANDWIDTH=200,CODECS="avc1",', + 'RESOLUTION=960x540,FRAME-RATE=60\n', + 'video\n', + ].join(''); + + const media = [ + '#EXTM3U\n', + '#EXT-X-TARGETDURATION:6\n', + '#EXT-X-PLAYLIST-TYPE:VOD\n', + '#EXT-X-KEY:METHOD=SAMPLE-AES,', + 'URI="fake",\n', + '#EXTINF:5,\n', + '#EXT-X-BYTERANGE:121090@616\n', + 'main.ts', + ].join(''); + + const error = new shaka.util.Error( + shaka.util.Error.Severity.CRITICAL, + shaka.util.Error.Category.MANIFEST, + Code.HLS_MSE_ENCRYPTED_MP2T_NOT_SUPPORTED); + + await verifyError(master, media, error, /* onCreateSegmentIndex= */ true); + }); + + describe('if required tags are missing', () => { /** * @param {string} master