Unreviewed gardening; update LayoutTests/media-source to the most recent version...
[WebKit-https.git] / LayoutTests / imported / w3c / web-platform-tests / media-source / mediasource-duration.html
1 <!DOCTYPE html>
2 <!--  Copyright © 2016 Chromium authors and World Wide Web Consortium, (Massachusetts Institute of Technology, ERCIM, Keio University, Beihang).  -->
3 <html>
4     <head>
5         <title>MediaSource.duration &amp; HTMLMediaElement.duration test cases.</title>
6         <script src="/resources/testharness.js"></script>
7         <script src="/resources/testharnessreport.js"></script>
8         <script src="mediasource-util.js"></script>
9     </head>
10     <body>
11         <div id="log"></div>
12         <script>
13
14           var subType = MediaSourceUtil.getSubType(MediaSourceUtil.AUDIO_ONLY_TYPE);
15           var manifestFilenameAudio = subType + "/test-a-128k-44100Hz-1ch-manifest.json";
16           var manifestFilenameVideo = subType + "/test-v-128k-320x240-30fps-10kfr-manifest.json";
17
18           function mediasource_truncated_duration_seek_test(testFunction, description, options)
19           {
20               return mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
21               {
22                   assert_greater_than(segmentInfo.duration, 2, 'Sufficient test media duration');
23
24                   var fullDuration = segmentInfo.duration;
25                   var seekTo = fullDuration / 2.0;
26                   var truncatedDuration = seekTo / 2.0;
27
28                   mediaElement.play();
29
30                   // Append all the segments
31                   test.expectEvent(sourceBuffer, 'updateend', 'sourceBuffer');
32                   test.expectEvent(mediaElement, 'playing', 'Playing triggered');
33                   sourceBuffer.appendBuffer(mediaData);
34
35                   test.waitForExpectedEvents(function()
36                   {
37                       test.expectEvent(mediaElement, 'seeking', 'seeking to seekTo');
38                       test.expectEvent(mediaElement, 'timeupdate', 'timeupdate while seeking to seekTo');
39                       test.expectEvent(mediaElement, 'seeked', 'seeked to seekTo');
40                       mediaElement.currentTime = seekTo;
41                       assert_true(mediaElement.seeking, 'mediaElement.seeking (to seekTo)');
42                   });
43
44                   test.waitForExpectedEvents(function()
45                   {
46                       assert_greater_than_equal(mediaElement.currentTime, seekTo, 'Playback time has reached seekTo');
47                       assert_false(mediaElement.seeking, 'mediaElement.seeking after seeked to seekTo');
48
49                       assert_false(sourceBuffer.updating, 'sourceBuffer.updating');
50
51                       sourceBuffer.remove(truncatedDuration, Infinity);
52
53                       assert_true(sourceBuffer.updating, 'sourceBuffer.updating');
54                       test.expectEvent(sourceBuffer, 'updatestart', 'sourceBuffer');
55                       test.expectEvent(sourceBuffer, 'update', 'sourceBuffer');
56                       test.expectEvent(sourceBuffer, 'updateend', 'sourceBuffer');
57                   });
58
59                   test.waitForExpectedEvents(function()
60                   {
61                       assert_greater_than_equal(mediaElement.currentTime, seekTo, 'Playback time has reached seekTo');
62                       assert_false(sourceBuffer.updating, 'sourceBuffer.updating');
63
64                       // Remove will not remove partial frames, so the resulting duration is the highest end time
65                       // of the track buffer ranges, and is greater than or equal to the highest coded frame
66                       // presentation time across all track buffer ranges. We first obtain the intersected track buffer
67                       // ranges end time and set the duration to that value.
68                       truncatedDuration = sourceBuffer.buffered.end(sourceBuffer.buffered.length-1);
69                       assert_less_than(truncatedDuration, seekTo,
70                                        'remove has removed the current playback position from at least one track buffer');
71
72                       mediaSource.duration = truncatedDuration;
73                       test.expectEvent(mediaElement, 'seeking', 'Seeking to truncated duration');
74
75                       // The actual duration may be slightly higher than truncatedDuration because the
76                       // duration is adjusted upwards if necessary to be the highest end time across all track buffer
77                       // ranges. Allow that increase here.
78                       assert_less_than_equal(truncatedDuration, mediaSource.duration,
79                                               'Duration should not be less than what was set');
80                       // Here, we assume no test media coded frame duration is longer than 100ms.
81                       assert_less_than(mediaSource.duration - truncatedDuration, 0.1);
82
83                       // Update our truncatedDuration to be the actual new duration.
84                       truncatedDuration = mediaSource.duration;
85
86                       assert_true(mediaElement.seeking, 'Seeking after setting truncatedDuration');
87                   });
88
89                   test.waitForExpectedEvents(function()
90                   {
91                       assert_equals(mediaElement.currentTime, truncatedDuration,
92                                     'Playback time is truncatedDuration while seeking');
93                       assert_true(mediaElement.seeking, 'mediaElement.seeking while seeking to truncatedDuration');
94                       assert_equals(mediaElement.duration, truncatedDuration,
95                                     'mediaElement truncatedDuration during seek to it');
96                       assert_equals(mediaSource.duration, truncatedDuration,
97                                     'mediaSource truncatedDuration during seek to it');
98
99                       testFunction(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData,
100                                    truncatedDuration);
101                   });
102               }, description, options);
103           }
104
105           mediasource_truncated_duration_seek_test(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer,
106                                                             mediaData, truncatedDuration)
107           {
108               // Tests that duration truncation below current playback position
109               // starts seek to new duration.
110               test.done();
111           }, 'Test seek starts on duration truncation below currentTime');
112
113           mediasource_truncated_duration_seek_test(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer,
114                                                             mediaData, truncatedDuration)
115           {
116               // The duration has been truncated at this point, and there is an
117               // outstanding seek pending.
118               test.expectEvent(sourceBuffer, 'updateend', 'updateend after appending more data');
119
120               test.expectEvent(mediaElement, 'timeupdate', 'timeupdate while finishing seek to truncatedDuration');
121               test.expectEvent(mediaElement, 'seeked', 'seeked to truncatedDuration');
122
123               // Allow seek to complete by appending more data beginning at the
124               // truncated duration timestamp.
125               sourceBuffer.timestampOffset = truncatedDuration;
126               sourceBuffer.appendBuffer(mediaData);
127
128               test.waitForExpectedEvents(function()
129               {
130                   assert_greater_than_equal(mediaElement.currentTime, truncatedDuration,
131                                             'Playback time has reached truncatedDuration');
132                   assert_approx_equals(mediaElement.duration, truncatedDuration + segmentInfo.duration, 0.05,
133                                        'mediaElement duration increased by new append');
134                   assert_equals(mediaSource.duration, mediaElement.duration,
135                                 'mediaSource duration increased by new append');
136                   assert_false(mediaElement.seeking, 'mediaElement.seeking after seeked to truncatedDuration');
137
138                   test.done();
139               });
140           }, 'Test appendBuffer completes previous seek to truncated duration');
141
142           mediasource_truncated_duration_seek_test(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer,
143                                                             mediaData, truncatedDuration)
144           {
145               // The duration has been truncated at this point, and there is an
146               // outstanding seek pending.
147               test.expectEvent(mediaSource, 'sourceended', 'endOfStream acknowledged');
148
149               test.expectEvent(mediaElement, 'timeupdate', 'timeupdate while finishing seek to truncatedDuration');
150               test.expectEvent(mediaElement, 'seeked', 'seeked to truncatedDuration');
151
152               // Call endOfStream() to complete the pending seek.
153               mediaSource.endOfStream();
154
155               test.waitForExpectedEvents(function()
156               {
157                   assert_greater_than_equal(mediaElement.currentTime, truncatedDuration,
158                                 'Playback time has reached truncatedDuration');
159                   // The mediaSource.readyState is "ended". Buffered ranges have been adjusted to the longest track.
160                   truncatedDuration = sourceBuffer.buffered.end(sourceBuffer.buffered.length-1);
161                   assert_equals(mediaElement.duration, truncatedDuration,
162                                 'mediaElement truncatedDuration after seek to it');
163                   assert_equals(mediaSource.duration, truncatedDuration,
164                                 'mediaSource truncatedDuration after seek to it');
165                   assert_false(mediaElement.seeking, 'mediaElement.seeking after seeked to truncatedDuration');
166
167                   test.done();
168               });
169           }, 'Test endOfStream completes previous seek to truncated duration');
170
171           mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
172           {
173               assert_greater_than(segmentInfo.duration, 2, 'Sufficient test media duration');
174
175               var fullDuration = segmentInfo.duration;
176               var newDuration = 0.5;
177
178               var expectedDurationChangeEventCount = 1;
179               var durationchangeEventCounter = 0;
180               var durationchangeEventHandler = test.step_func(function(event)
181               {
182                   assert_equals(mediaElement.duration, mediaSource.duration, 'mediaElement newDuration');
183                   // Final duration may be greater than originally set as per MSE's 2.4.6 Duration change
184                   // Adjust newDuration accordingly.
185                   assert_less_than_equal(newDuration, mediaSource.duration, 'mediaSource newDuration');
186                   durationchangeEventCounter++;
187               });
188
189               mediaElement.play();
190
191               // Append all the segments
192               test.expectEvent(sourceBuffer, 'updateend', 'sourceBuffer');
193               test.expectEvent(mediaElement, 'playing', 'Playing triggered');
194               sourceBuffer.appendBuffer(mediaData);
195
196               test.waitForExpectedEvents(function()
197               {
198                   assert_less_than(mediaElement.currentTime, newDuration / 2, 'mediaElement currentTime');
199
200                   assert_false(sourceBuffer.updating, "updating");
201
202                   // Truncate duration. This should result in one 'durationchange' fired.
203                   sourceBuffer.remove(newDuration, Infinity);
204
205                   assert_true(sourceBuffer.updating, "updating");
206                   test.expectEvent(sourceBuffer, 'updatestart', 'sourceBuffer');
207                   test.expectEvent(sourceBuffer, 'update', 'sourceBuffer');
208                   test.expectEvent(sourceBuffer, 'updateend', 'sourceBuffer');
209               });
210
211               test.waitForExpectedEvents(function()
212               {
213                   // Media load also fires 'durationchange' event, so only start counting them now.
214                   mediaElement.addEventListener('durationchange', durationchangeEventHandler);
215
216                   assert_false(sourceBuffer.updating, "updating");
217
218                   // Truncate duration. This should result in one 'durationchange' fired.
219                   mediaSource.duration = newDuration;
220
221                   // Final duration may be greater than originally set as per MSE's 2.4.6 Duration change
222                   // Adjust newDuration accordingly.
223                   assert_true(newDuration <= mediaSource.duration, 'adjusted duration');
224                   newDuration = mediaSource.duration;
225
226                   // Set duration again to make sure it does not trigger another 'durationchange' event.
227                   mediaSource.duration = newDuration;
228
229                   // Mark endOfStream so that playback can reach 'ended' at the new duration.
230                   test.expectEvent(mediaSource, 'sourceended', 'endOfStream acknowledged');
231                   mediaSource.endOfStream();
232
233                   // endOfStream can change duration slightly.
234                   // Allow for one more 'durationchange' event only in this case.
235                   var currentDuration = mediaSource.duration;
236                   if (currentDuration != newDuration) {
237                       newDuration = currentDuration;
238                       ++expectedDurationChangeEventCount;
239                   }
240
241                   // Allow media to play to end while counting 'durationchange' events.
242                   test.expectEvent(mediaElement, 'ended', 'Playback ended');
243                   test.waitForExpectedEvents(function()
244                   {
245                       mediaElement.removeEventListener('durationchange', durationchangeEventHandler);
246                       assert_equals(durationchangeEventCounter, expectedDurationChangeEventCount, 'durationchanges');
247                       test.done();
248                   });
249               });
250           }, 'Test setting same duration multiple times does not fire duplicate durationchange');
251
252           mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
253           {
254               assert_greater_than(segmentInfo.duration, 2, 'Sufficient test media duration');
255
256               var fullDuration = segmentInfo.duration;
257               var newDuration = fullDuration / 2;
258
259               // Append all the segments
260               test.expectEvent(sourceBuffer, 'updateend', 'sourceBuffer');
261               test.expectEvent(mediaElement, 'loadedmetadata', 'mediaElement');
262               sourceBuffer.appendBuffer(mediaData);
263
264               test.waitForExpectedEvents(function()
265               {
266                   assert_false(sourceBuffer.updating, "updating");
267
268                   assert_throws("InvalidStateError", function()
269                   {
270                       mediaSource.duration = newDuration;
271                   }, "duration");
272
273                   test.done();
274               });
275           }, 'Test setting the duration to less than the highest starting presentation timestamp will throw');
276
277           mediasource_test(function(test, mediaElement, mediaSource)
278           {
279               mediaElement.addEventListener("error", test.unreached_func("Unexpected event 'error'"));
280               MediaSourceUtil.fetchManifestAndData(test, manifestFilenameAudio, function(typeAudio, dataAudio)
281               {
282                   MediaSourceUtil.fetchManifestAndData(test, manifestFilenameVideo, function(typeVideo, dataVideo)
283                   {
284                       var sourceBufferAudio = mediaSource.addSourceBuffer(typeAudio);
285                       var sourceBufferVideo = mediaSource.addSourceBuffer(typeVideo);
286                       var newDuration = 1.2;
287
288                       sourceBufferAudio.appendWindowEnd = 2.0;
289                       sourceBufferAudio.appendWindowStart = newDuration / 2.0;
290                       sourceBufferAudio.appendBuffer(dataAudio);
291
292                       sourceBufferVideo.appendWindowEnd = 2.0;
293                       sourceBufferVideo.appendWindowStart = newDuration * 1.3;
294                       sourceBufferVideo.appendBuffer(dataVideo);
295
296                       test.expectEvent(sourceBufferAudio, "updateend");
297                       test.expectEvent(sourceBufferVideo, "updateend");
298                       test.waitForExpectedEvents(function()
299                       {
300                           assert_equals(sourceBufferAudio.buffered.length, 1);
301                           assert_equals(sourceBufferVideo.buffered.length, 1);
302                           assert_less_than(sourceBufferAudio.buffered.start(0), newDuration);
303                           assert_greater_than(sourceBufferVideo.buffered.start(0), newDuration);
304                           assert_throws("InvalidStateError", function () { mediaSource.duration = newDuration; });
305                           test.done();
306                       });
307                   });
308               });
309           }, "Truncating the duration throws an InvalidStateError exception when new duration is less than the highest buffered range start time of one of the track buffers");
310
311           mediasource_test(function(test, mediaElement, mediaSource)
312           {
313               mediaElement.addEventListener("error", test.unreached_func("Unexpected event 'error'"));
314               MediaSourceUtil.fetchManifestAndData(test, manifestFilenameAudio, function(typeAudio, dataAudio)
315               {
316                   MediaSourceUtil.fetchManifestAndData(test, manifestFilenameVideo, function(typeVideo, dataVideo)
317                   {
318                       var sourceBufferAudio = mediaSource.addSourceBuffer(typeAudio);
319                       var sourceBufferVideo = mediaSource.addSourceBuffer(typeVideo);
320
321                       // Buffer audio [0.8,1.8)
322                       sourceBufferAudio.timestampOffset = 0.8;
323                       sourceBufferAudio.appendWindowEnd = 1.8;
324                       sourceBufferAudio.appendBuffer(dataAudio);
325
326                       // Buffer video [1.5,3)
327                       sourceBufferVideo.timestampOffset = 1.5;
328                       sourceBufferVideo.appendWindowEnd = 3;
329                       sourceBufferVideo.appendBuffer(dataVideo);
330
331                       test.expectEvent(sourceBufferAudio, "updateend");
332                       test.expectEvent(sourceBufferVideo, "updateend");
333                       test.waitForExpectedEvents(function()
334                       {
335                           var newDuration = 2.0;
336
337                           // Verify the test setup
338                           assert_equals(sourceBufferAudio.buffered.length, 1);
339                           assert_equals(sourceBufferVideo.buffered.length, 1);
340                           assert_greater_than(sourceBufferAudio.buffered.end(0), 1.5);
341                           assert_less_than(sourceBufferAudio.buffered.end(0), newDuration);
342                           assert_less_than(sourceBufferVideo.buffered.start(0), newDuration);
343                           assert_greater_than(sourceBufferVideo.buffered.end(0), newDuration + 0.5);
344
345                           // Verify the expected error
346                           // We assume relocated test video has at least one coded
347                           // frame presentation interval which fits in [>2.0,>2.5)
348                           assert_throws("InvalidStateError", function () { mediaSource.duration = newDuration; });
349                           test.done();
350                       });
351                   });
352               });
353           }, "Truncating the duration throws an InvalidStateError exception when new duration is less than a buffered coded frame presentation time");
354
355           mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
356           {
357               assert_less_than(segmentInfo.duration, 60, 'Sufficient test media duration');
358               sourceBuffer.appendBuffer(mediaData);
359               test.expectEvent(sourceBuffer, 'updateend', 'Media data appended to the SourceBuffer');
360               test.waitForExpectedEvents(function()
361               {
362                   mediaSource.duration = 60;
363                   assert_false(sourceBuffer.updating, 'No SourceBuffer update when duration is increased');
364                   test.done();
365               });
366           }, 'Increasing the duration does not trigger any SourceBuffer update');
367
368           mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
369           {
370               assert_greater_than(segmentInfo.duration, 2, 'Sufficient test media duration');
371               mediaElement.play();
372               sourceBuffer.appendBuffer(mediaData);
373               test.expectEvent(sourceBuffer, 'updateend', 'Media data appended to the SourceBuffer');
374               test.waitForExpectedEvents(function()
375               {
376                   mediaSource.duration = 60;
377                   assert_false(sourceBuffer.updating, 'No SourceBuffer update when duration is increased');
378                   test.done();
379               });
380           }, 'Increasing the duration during media playback does not trigger any SourceBuffer update');
381         </script>
382     </body>
383 </html>