diff --git a/demo/config.js b/demo/config.js index 74a604b87b..25ff1b067f 100644 --- a/demo/config.js +++ b/demo/config.js @@ -444,6 +444,9 @@ shakaDemo.Config = class { .addNumberInput_('Gap detection threshold', 'streaming.gapDetectionThreshold', /* canBeDecimal= */ true) + .addNumberInput_('Gap padding', + 'streaming.gapPadding', + /* canBeDecimal= */ true) .addNumberInput_('Gap Jump Timer Time', 'streaming.gapJumpTimerTime', /* canBeDecimal= */ true) .addNumberInput_('Buffering Goal', 'streaming.bufferingGoal', diff --git a/externs/shaka/player.js b/externs/shaka/player.js index df096eb9b1..df33cadbd3 100644 --- a/externs/shaka/player.js +++ b/externs/shaka/player.js @@ -1532,6 +1532,7 @@ shaka.extern.LiveSyncConfiguration; * alwaysStreamText: boolean, * startAtSegmentBoundary: boolean, * gapDetectionThreshold: number, + * gapPadding: number, * gapJumpTimerTime: number, * durationBackoff: number, * safeSeekOffset: number, @@ -1625,6 +1626,13 @@ shaka.extern.LiveSyncConfiguration; * jump. *
* Defaults to 0.5. + * @property {number} gapPadding + * Padding added only for Xbox, Legacy Edge and Tizen. + * Based on our research (specific to Tizen), the gapPadding value must be + * greater than your GOP length. + * It’s crucial to verify this value according to your actual stream. + *
+ * Defaults to 0.01 for Xbox and Legacy Edge, Tizen at 2. * @property {number} gapJumpTimerTime * The polling time in seconds to check for gaps in the media. *
diff --git a/lib/media/gap_jumping_controller.js b/lib/media/gap_jumping_controller.js index c2267f74a6..6741d53d4e 100644 --- a/lib/media/gap_jumping_controller.js +++ b/lib/media/gap_jumping_controller.js @@ -223,8 +223,10 @@ shaka.media.GapJumpingController = class { // often rounds value we want to set as currentTime and we are not able // to jump over the gap. if (shaka.util.Platform.isLegacyEdge() || - shaka.util.Platform.isXboxOne()) { - jumpTo = Math.ceil((jumpTo + 0.01) * 100) / 100; + shaka.util.Platform.isXboxOne() || + shaka.util.Platform.isTizen()) { + const gapPadding = this.config_.gapPadding; + jumpTo = Math.ceil((jumpTo + gapPadding) * 100) / 100; } const seekEnd = this.timeline_.getSeekRangeEnd(); if (jumpTo >= seekEnd) { diff --git a/lib/util/player_configuration.js b/lib/util/player_configuration.js index efffc7a201..ddeb044b8a 100644 --- a/lib/util/player_configuration.js +++ b/lib/util/player_configuration.js @@ -206,6 +206,7 @@ shaka.util.PlayerConfiguration = class { alwaysStreamText: false, startAtSegmentBoundary: false, gapDetectionThreshold: 0.5, + gapPadding: 0.01, gapJumpTimerTime: 0.25 /* seconds */, durationBackoff: 1, // Offset by 5 seconds since Chromecast takes a few seconds to start @@ -283,6 +284,10 @@ shaka.util.PlayerConfiguration = class { streaming.stallSkip = 0; } + if (shaka.util.Platform.isTizen()) { + streaming.gapPadding = 2; + } + const offline = { // We need to set this to a throw-away implementation for now as our // default implementation will need to reference other fields in the diff --git a/test/media/playhead_unit.js b/test/media/playhead_unit.js index cb8dc26a6b..9472a25c3d 100644 --- a/test/media/playhead_unit.js +++ b/test/media/playhead_unit.js @@ -151,6 +151,18 @@ describe('Playhead', () => { playhead.release(); }); + function calculateGap(time) { + let jumpTo = time; + if (shaka.util.Platform.isLegacyEdge() || + shaka.util.Platform.isXboxOne() || + shaka.util.Platform.isTizen()) { + const gapPadding = shaka.util.PlayerConfiguration.createDefault() + .streaming.gapPadding; + jumpTo = Math.ceil((jumpTo + gapPadding) * 100) / 100; + } + return jumpTo; + } + function setMockDate(seconds) { const minutes = Math.floor(seconds / 60); seconds %= 60; @@ -900,7 +912,7 @@ describe('Playhead', () => { start: 5, waitingAt: 10, expectEvent: true, - expectedEndTime: 11, + expectedEndTime: calculateGap(11), }); playingTest('won\'t skip a buffered range', { @@ -909,7 +921,7 @@ describe('Playhead', () => { start: 5, waitingAt: 10, expectEvent: true, - expectedEndTime: 11, + expectedEndTime: calculateGap(11), }); playingTest('will jump gap into last buffer', { @@ -918,7 +930,7 @@ describe('Playhead', () => { start: 15, waitingAt: 20, expectEvent: true, - expectedEndTime: 21, + expectedEndTime: calculateGap(21), }); }); // with small gaps @@ -928,7 +940,7 @@ describe('Playhead', () => { start: 5, waitingAt: 10, expectEvent: true, - expectedEndTime: 30, + expectedEndTime: calculateGap(30), }); playingTest('will only jump one buffer', { @@ -937,7 +949,7 @@ describe('Playhead', () => { start: 5, waitingAt: 10, expectEvent: true, - expectedEndTime: 30, + expectedEndTime: calculateGap(30), }); playingTest('will jump into last buffer', { @@ -946,7 +958,7 @@ describe('Playhead', () => { start: 24, waitingAt: 30, expectEvent: true, - expectedEndTime: 50, + expectedEndTime: calculateGap(50), }); }); // with large gaps @@ -1019,7 +1031,7 @@ describe('Playhead', () => { start: 3, seekTo: 10.4, expectEvent: true, - expectedEndTime: 11, + expectedEndTime: calculateGap(11), }); seekTest('won\'t jump multiple buffers', { @@ -1028,7 +1040,7 @@ describe('Playhead', () => { start: 3, seekTo: 10.4, expectEvent: true, - expectedEndTime: 11, + expectedEndTime: calculateGap(11), }); seekTest('will jump into last range with seeking', { @@ -1037,7 +1049,7 @@ describe('Playhead', () => { start: 3, seekTo: 20.5, expectEvent: true, - expectedEndTime: 21, + expectedEndTime: calculateGap(21), }); seekTest('treats large gaps as small if playhead near end', { @@ -1045,7 +1057,7 @@ describe('Playhead', () => { start: 3, seekTo: 29.2, expectEvent: true, - expectedEndTime: 30, + expectedEndTime: calculateGap(30), }); }); // with small gaps @@ -1055,7 +1067,7 @@ describe('Playhead', () => { start: 5, seekTo: 12, expectEvent: true, - expectedEndTime: 30, + expectedEndTime: calculateGap(30), }); }); // with large gaps }); // with buffered seeks @@ -1080,7 +1092,7 @@ describe('Playhead', () => { start: 4, seekTo: 0, expectEvent: true, - expectedEndTime: 0.2, + expectedEndTime: calculateGap(0.2), }); seekTest('will jump when seeking into gap', { @@ -1090,7 +1102,7 @@ describe('Playhead', () => { start: 3, seekTo: 30.2, expectEvent: true, - expectedEndTime: 31, + expectedEndTime: calculateGap(31), }); seekTest('will jump when seeking to the end of a range', { @@ -1100,7 +1112,7 @@ describe('Playhead', () => { start: 3, seekTo: 30, expectEvent: true, - expectedEndTime: 31, + expectedEndTime: calculateGap(31), }); seekTest('won\'t jump when past end', { @@ -1141,7 +1153,7 @@ describe('Playhead', () => { start: 24, seekTo: 1.6, expectEvent: true, - expectedEndTime: 2, + expectedEndTime: calculateGap(2), }); }); // with small gaps @@ -1152,7 +1164,7 @@ describe('Playhead', () => { start: 25, seekTo: 0, expectEvent: true, - expectedEndTime: 20, + expectedEndTime: calculateGap(20), }); seekTest('will jump large gaps', { @@ -1162,7 +1174,7 @@ describe('Playhead', () => { start: 3, seekTo: 32, expectEvent: true, - expectedEndTime: 40, + expectedEndTime: calculateGap(40), }); }); // with large gaps }); // with unbuffered seeks @@ -1237,7 +1249,7 @@ describe('Playhead', () => { jasmine.clock().tick(500); expect(seekCount).toBe(1); - expect(currentTime).toBe(10); + expect(currentTime).toBe(calculateGap(10)); }); it('doesn\'t gap jump if paused', () => { @@ -1287,7 +1299,7 @@ describe('Playhead', () => { jasmine.clock().tick(500); // There SHOULD have been a gap jump. - expect(video.currentTime).toBe(10); + expect(video.currentTime).toBe(calculateGap(10)); }); // Regression test for https://github.com/shaka-project/shaka-player/issues/3451