diff --git a/karma.conf.js b/karma.conf.js
index 3c99eebff5..20fbd77ace 100644
--- a/karma.conf.js
+++ b/karma.conf.js
@@ -257,6 +257,7 @@ module.exports = (config) => {
{pattern: 'test/test/assets/dash-multi-codec/*', included: false},
{pattern: 'test/test/assets/dash-multi-codec-ec3/*', included: false},
{pattern: 'test/test/assets/3675/*', included: false},
+ {pattern: 'test/test/assets/7401/*', included: false},
{pattern: 'test/test/assets/6339/*', included: false},
{pattern: 'test/test/assets/dash-aes-128/*', included: false},
{pattern: 'test/test/assets/dash-clearkey/*', included: false},
diff --git a/lib/dash/dash_parser.js b/lib/dash/dash_parser.js
index 74ef240013..9f2721a9ca 100644
--- a/lib/dash/dash_parser.js
+++ b/lib/dash/dash_parser.js
@@ -1341,11 +1341,13 @@ shaka.dash.DashParser = class {
for (let i = 0; i < periodNodes.length; i++) {
const elem = periodNodes[i];
const next = periodNodes[i + 1];
- const start = /** @type {number} */ (
+ let start = /** @type {number} */ (
TXml.parseAttr(elem, 'start', TXml.parseDuration, prevEnd));
const periodId = elem.attributes['id'];
const givenDuration =
TXml.parseAttr(elem, 'duration', TXml.parseDuration);
+ start = (i == 0 && start == 0 && this.isTransitionFromDynamicToStatic_) ?
+ seekRangeStart : start;
let periodDuration = null;
if (next) {
@@ -1355,7 +1357,7 @@ shaka.dash.DashParser = class {
const nextStart =
TXml.parseAttr(next, 'start', TXml.parseDuration);
if (nextStart != null) {
- periodDuration = nextStart - start;
+ periodDuration = nextStart - start + seekRangeStart;
}
} else if (presentationDuration != null) {
// "The Period extends until the Period.start of the next Period, or
diff --git a/test/player_integration.js b/test/player_integration.js
index 455c0779d2..75132ba94d 100644
--- a/test/player_integration.js
+++ b/test/player_integration.js
@@ -102,6 +102,46 @@ describe('Player', () => {
expect(seekRange.start).toBeCloseTo(start);
});
});
+ describe('Live to VOD', () => {
+ it('playback transition when current time is in the past', 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/7401/dash_' + manifestNumber + '.mpd',
+ ];
+ console.log('getting manifest', request.uris);
+ });
+ player.configure('streaming.bufferBehind', 1);
+ player.configure('streaming.evictionGoal', 1);
+ // Play the stream .
+ await player.load('/base/test/test/assets/7401/dash_0.mpd', 1020);
+ await video.play();
+ video.pause();
+ // 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);
+ // wait for Dynamic to static
+ await waiter.waitUntilVodTransition(video);
+ expect(player.isLive()).toBe(false);
+ // set the playback to 1020 in middle of the second period
+ video.currentTime = 1020;
+ await video.play();
+ await waiter.waitForEnd(video);
+ // The stream should have transitioned to VOD by now.
+ expect(player.isLive()).toBe(false);
+ });
+ });
describe('attach', () => {
beforeEach(async () => {
diff --git a/test/test/assets/7401/chunk-stream0-00001.m4s b/test/test/assets/7401/chunk-stream0-00001.m4s
new file mode 100644
index 0000000000..b423109cbc
Binary files /dev/null and b/test/test/assets/7401/chunk-stream0-00001.m4s differ
diff --git a/test/test/assets/7401/chunk-stream0-00002.m4s b/test/test/assets/7401/chunk-stream0-00002.m4s
new file mode 100644
index 0000000000..6e805b076b
Binary files /dev/null and b/test/test/assets/7401/chunk-stream0-00002.m4s differ
diff --git a/test/test/assets/7401/chunk-stream0-00003.m4s b/test/test/assets/7401/chunk-stream0-00003.m4s
new file mode 100644
index 0000000000..9a357bb2c7
Binary files /dev/null and b/test/test/assets/7401/chunk-stream0-00003.m4s differ
diff --git a/test/test/assets/7401/chunk-stream0-00004.m4s b/test/test/assets/7401/chunk-stream0-00004.m4s
new file mode 100644
index 0000000000..de1e8191da
Binary files /dev/null and b/test/test/assets/7401/chunk-stream0-00004.m4s differ
diff --git a/test/test/assets/7401/chunk-stream0-00005.m4s b/test/test/assets/7401/chunk-stream0-00005.m4s
new file mode 100644
index 0000000000..a00d931eea
Binary files /dev/null and b/test/test/assets/7401/chunk-stream0-00005.m4s differ
diff --git a/test/test/assets/7401/chunk-stream0-00006.m4s b/test/test/assets/7401/chunk-stream0-00006.m4s
new file mode 100644
index 0000000000..dce9209c3f
Binary files /dev/null and b/test/test/assets/7401/chunk-stream0-00006.m4s differ
diff --git a/test/test/assets/7401/chunk-stream0-00007.m4s b/test/test/assets/7401/chunk-stream0-00007.m4s
new file mode 100644
index 0000000000..0a30cb49ca
Binary files /dev/null and b/test/test/assets/7401/chunk-stream0-00007.m4s differ
diff --git a/test/test/assets/7401/dash_0.mpd b/test/test/assets/7401/dash_0.mpd
new file mode 100644
index 0000000000..d575921096
--- /dev/null
+++ b/test/test/assets/7401/dash_0.mpd
@@ -0,0 +1,52 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/test/test/assets/7401/dash_1.mpd b/test/test/assets/7401/dash_1.mpd
new file mode 100644
index 0000000000..cc415e0b76
--- /dev/null
+++ b/test/test/assets/7401/dash_1.mpd
@@ -0,0 +1,52 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/test/test/assets/7401/dash_2.mpd b/test/test/assets/7401/dash_2.mpd
new file mode 100644
index 0000000000..e8b5252d75
--- /dev/null
+++ b/test/test/assets/7401/dash_2.mpd
@@ -0,0 +1,48 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/test/test/assets/7401/init-stream0.m4s b/test/test/assets/7401/init-stream0.m4s
new file mode 100644
index 0000000000..ba6f961f21
Binary files /dev/null and b/test/test/assets/7401/init-stream0.m4s differ
diff --git a/test/test/util/waiter.js b/test/test/util/waiter.js
index 42f6447975..4035a9b489 100644
--- a/test/test/util/waiter.js
+++ b/test/test/util/waiter.js
@@ -143,6 +143,41 @@ shaka.test.Waiter = class {
return this.waitUntilGeneric_(goalName, p, cleanup, mediaElement);
}
+ /**
+ * Wait for the video player to fetch the static manifest.
+ * Promise is resolved player.isLive is false.
+ *
+ * @param {!HTMLMediaElement} mediaElement
+ * @return {!Promise}
+ */
+ waitUntilVodTransition(mediaElement) {
+ // The name of what we're waiting for
+ const goalName = 'manifest to be static';
+
+ // The cleanup on timeout
+ let timer = null;
+ const cleanup = () => {
+ if (timer) {
+ timer.stop();
+ }
+ };
+
+ // The conditions for success
+ const p = new Promise((resolve) => {
+ const check = () => {
+ if (!this.player_.isLive()) {
+ cleanup();
+ resolve();
+ }
+ };
+
+ timer = new shaka.util.Timer(check);
+ timer.tickEvery(/* seconds= */ 1);
+ });
+
+ return this.waitUntilGeneric_(goalName, p, cleanup, mediaElement);
+ }
+
/**
* Wait for the video playhead to reach a certain target time.
* If the playhead reaches |timeGoal| or the video ends before |timeout|