0201bdab by Lee Whitaker

Initial tests for allow_cache, extinf, mediasequence, and byterange.

1 parent 7452d792
...@@ -73,11 +73,11 @@ ...@@ -73,11 +73,11 @@
73 ok(parsedData); 73 ok(parsedData);
74 }); 74 });
75 75
76 test('should populate the manifest data object', function() { 76 test('valid manifest should populate the manifest data object', function() {
77 var data = m3u8parser.parse(window.playlistData); 77 var data = m3u8parser.parse(window.playlistData);
78 78
79 notEqual(data, null, 'data is not NULL'); 79 notEqual(data, null, 'data is not NULL');
80 equal(data.invalidReasons.length, 0, 'data has 0 invalid reasons'); 80 equal(data.invalidReasons.length, 0, 'Errors object should not be empty.');
81 equal(data.hasValidM3UTag, true, 'data has valid EXTM3U'); 81 equal(data.hasValidM3UTag, true, 'data has valid EXTM3U');
82 equal(data.targetDuration, 10, 'data has correct TARGET DURATION'); 82 equal(data.targetDuration, 10, 'data has correct TARGET DURATION');
83 equal(data.allowCache, "NO", 'acceptable ALLOW CACHE'); 83 equal(data.allowCache, "NO", 'acceptable ALLOW CACHE');
...@@ -101,7 +101,8 @@ ...@@ -101,7 +101,8 @@
101 tag. 101 tag.
102 102
103 The EXT-X-PLAYLIST-TYPE tag MUST NOT appear in a Master Playlist. 103 The EXT-X-PLAYLIST-TYPE tag MUST NOT appear in a Master Playlist.
104 */ 104 */
105
105 test('should have parsed VOD playlist type', function() { 106 test('should have parsed VOD playlist type', function() {
106 var 107 var
107 playlistTemplate = Handlebars.compile(window.playlist_type_template), 108 playlistTemplate = Handlebars.compile(window.playlist_type_template),
...@@ -110,7 +111,7 @@ ...@@ -110,7 +111,7 @@
110 data = m3u8parser.parse(playlistData); 111 data = m3u8parser.parse(playlistData);
111 112
112 notEqual(data, null, 'data is not NULL'); 113 notEqual(data, null, 'data is not NULL');
113 equal(data.invalidReasons.length, 0, 'data has 0 invalid reasons'); 114 equal(data.invalidReasons.length, 0, 'Errors object should not be empty.');
114 equal(data.playlistType, "VOD", 'acceptable PLAYLIST TYPE'); 115 equal(data.playlistType, "VOD", 'acceptable PLAYLIST TYPE');
115 }); 116 });
116 117
...@@ -121,7 +122,7 @@ ...@@ -121,7 +122,7 @@
121 playlistData = playlistTemplate(testData), 122 playlistData = playlistTemplate(testData),
122 data = m3u8parser.parse(playlistData); 123 data = m3u8parser.parse(playlistData);
123 notEqual(data, null, 'data is not NULL'); 124 notEqual(data, null, 'data is not NULL');
124 equal(data.invalidReasons.length, 0, 'data has 0 invalid reasons'); 125 equal(data.invalidReasons.length, 0, 'Errors object should not be empty.');
125 equal(data.playlistType, "EVENT", 'acceptable PLAYLIST TYPE'); 126 equal(data.playlistType, "EVENT", 'acceptable PLAYLIST TYPE');
126 }); 127 });
127 128
...@@ -133,7 +134,8 @@ ...@@ -133,7 +134,8 @@
133 data = m3u8parser.parse(playlistData); 134 data = m3u8parser.parse(playlistData);
134 135
135 notEqual(data, null, 'data is not NULL'); 136 notEqual(data, null, 'data is not NULL');
136 equal(data.invalidReasons.length, 0, 'data has 0 invalid reasons'); 137 equal(data.invalidReasons.length, 0, 'Errors object should not be empty.');
138 equal(data.warnings, 'EXT-X-PLAYLIST-TYPE was empty or missing. Assuming VOD');
137 equal(data.playlistType, "VOD", 'acceptable PLAYLIST TYPE'); 139 equal(data.playlistType, "VOD", 'acceptable PLAYLIST TYPE');
138 }); 140 });
139 141
...@@ -145,18 +147,19 @@ ...@@ -145,18 +147,19 @@
145 data = m3u8parser.parse(playlistData); 147 data = m3u8parser.parse(playlistData);
146 notEqual(data, null, 'data is not NULL'); 148 notEqual(data, null, 'data is not NULL');
147 equal(data.invalidReasons.length, 1, 'data has 1 invalid reasons'); 149 equal(data.invalidReasons.length, 1, 'data has 1 invalid reasons');
148 equal(data.invalidReasons[0], 'Invalid Playlist Type Value: baklsdhfajsdf'); 150 equal(data.invalidReasons[0], 'Invalid Playlist Type Value: \'baklsdhfajsdf\'');
149 }); 151 });
150 152
151 test('should have an invalid reason due to invalid playlist type', function() { 153 test('should have assumed VOD playlist type is empty', function() {
152 var 154 var
153 playlistTemplate = Handlebars.compile(window.playlist_type_template), 155 playlistTemplate = Handlebars.compile(window.playlist_type_template),
154 testData = {playlistType: ''}, 156 testData = {playlistType: ''},
155 playlistData = playlistTemplate(testData), 157 playlistData = playlistTemplate(testData),
156 data = m3u8parser.parse(playlistData); 158 data = m3u8parser.parse(playlistData);
157 notEqual(data, null, 'data is not NULL'); 159 notEqual(data, null, 'data is not NULL');
158 equal(data.invalidReasons.length, 1, 'data has 1 invalid reasons'); 160 equal(data.invalidReasons.length, 0, 'Errors object should not be empty.');
159 equal(data.invalidReasons[0], 'Invalid Playlist Type Value: \'\''); 161 equal(data.warnings, 'EXT-X-PLAYLIST-TYPE was empty or missing. Assuming VOD');
162 equal(data.playlistType, "VOD", 'acceptable PLAYLIST TYPE');
160 }); 163 });
161 164
162 /*3.4.2. EXT-X-TARGETDURATION 165 /*3.4.2. EXT-X-TARGETDURATION
...@@ -190,33 +193,43 @@ ...@@ -190,33 +193,43 @@
190 test('NaN target duration', function() { 193 test('NaN target duration', function() {
191 var 194 var
192 playlistTemplate = Handlebars.compile(window.playlist_target_duration_template), 195 playlistTemplate = Handlebars.compile(window.playlist_target_duration_template),
193 testData = {targetDuration: '10'}, 196 testData = {targetDuration: 'string'},
194 playlistData = playlistTemplate(testData), 197 playlistData = playlistTemplate(testData),
195 data = m3u8parser.parse(playlistData); 198 data = m3u8parser.parse(playlistData);
196 notEqual(data, null, 'data is not NULL'); 199 console.log(playlistData);
197 equal(data.targetDuration, 10, 'data has correct TARGET DURATION'); 200 console.log(data.targetDuration);
198 equal(data.invalidReasons.length, 0, 'data has 1 invalid reasons'); 201 notEqual(data, null, 'data is not NULL');
199
200 testData = {targetDuration: 'string'};
201 playlistData = playlistTemplate(testData);
202 data = m3u8parser.parse(playlistData);
203 notEqual(data.invalidReasons, null, 'invalidReasons is not NULL'); 202 notEqual(data.invalidReasons, null, 'invalidReasons is not NULL');
204 equal(data.invalidReasons.length, 1, 'data has 1 invalid reasons'); 203 equal(data.invalidReasons.length, 1, 'data has 0 invalid reasons');
205 equal(data.invalidReasons[0], 'Invalid Target Duration Value: string'); 204 equal(data.invalidReasons[0], 'Invalid Target Duration Value: \'NaN\'');
205 });
206 206
207 testData = {targetDuration: ''}; 207 test('empty target duration', function() {
208 playlistData = playlistTemplate(testData); 208 var
209 data = m3u8parser.parse(playlistData); 209 playlistTemplate = Handlebars.compile(window.playlist_target_duration_template),
210 testData = {targetDuration: '\'\''},
211 playlistData = playlistTemplate(testData),
212 data = m3u8parser.parse(playlistData);
213 console.log(playlistData);
214 console.log(data.targetDuration);
215 notEqual(data, null, 'data is not NULL');
210 notEqual(data.invalidReasons, null, 'invalidReasons is not NULL'); 216 notEqual(data.invalidReasons, null, 'invalidReasons is not NULL');
211 equal(data.invalidReasons.length, 1, 'data has 1 invalid reasons'); 217 equal(data.invalidReasons.length, 1, 'data has 1 invalid reasons');
212 equal(data.invalidReasons[0], 'Invalid Target Duration Value: \'\''); 218 equal(data.invalidReasons[0], 'Invalid Target Duration Value: \'NaN\'');
219 });
213 220
214 testData = {}; 221 test('undefined target duration', function() {
215 playlistData = playlistTemplate(testData); 222 var
223 playlistTemplate = Handlebars.compile(window.playlist_target_duration_template),
224 testData = {},
225 playlistData = playlistTemplate(testData),
226 data = m3u8parser.parse(playlistData);
227 console.log(playlistData);
228 console.log(data.targetDuration);
216 notEqual(data, null, 'data is not NULL'); 229 notEqual(data, null, 'data is not NULL');
217 notEqual(data.invalidReasons, null, 'invalidReasons is not NULL'); 230 notEqual(data.invalidReasons, null, 'invalidReasons is not NULL');
218 equal(data.invalidReasons.length, 1, 'data has 1 invalid reasons'); 231 equal(data.invalidReasons.length, 1, 'data has 1 invalid reasons');
219 equal(data.invalidReasons[0], 'Invalid Target Duration Value: '+ undefined); 232 equal(data.invalidReasons[0], 'Invalid Target Duration Value: \'undefined\'');
220 233
221 }); 234 });
222 235
...@@ -251,11 +264,11 @@ ...@@ -251,11 +264,11 @@
251 MEDIA-SEQUENCE tag then the sequence number of the first segment in 264 MEDIA-SEQUENCE tag then the sequence number of the first segment in
252 the playlist SHALL be considered to be 0. A client MUST NOT assume 265 the playlist SHALL be considered to be 0. A client MUST NOT assume
253 that segments with the same sequence number in different Media 266 that segments with the same sequence number in different Media
254 Playlists contain matching content. 267 Playlists contain matching content.
255 268
256 A media URI is not required to contain its sequence number. 269 A media URI is not required to contain its sequence number.
257 */ 270 */
258 271
259 test('media sequence is valid in the playlist', function() { 272 test('media sequence is valid in the playlist', function() {
260 var 273 var
261 playlistTemplate = Handlebars.compile(window.playlist_media_sequence_template), 274 playlistTemplate = Handlebars.compile(window.playlist_media_sequence_template),
...@@ -265,7 +278,7 @@ ...@@ -265,7 +278,7 @@
265 278
266 notEqual(data, null, 'data is not NULL'); 279 notEqual(data, null, 'data is not NULL');
267 notEqual(data.invalidReasons, null, 'invalidReasons is not NULL'); 280 notEqual(data.invalidReasons, null, 'invalidReasons is not NULL');
268 equal(data.invalidReasons.length, 0, 'data has 0 invalid reasons'); 281 equal(data.invalidReasons.length, 0, 'Errors object should not be empty.');
269 equal(data.mediaSequence, 0, 'MEDIA SEQUENCE is correct'); 282 equal(data.mediaSequence, 0, 'MEDIA SEQUENCE is correct');
270 }); 283 });
271 284
...@@ -278,7 +291,7 @@ ...@@ -278,7 +291,7 @@
278 291
279 notEqual(data, null, 'data is not NULL'); 292 notEqual(data, null, 'data is not NULL');
280 notEqual(data.invalidReasons, null, 'invalidReasons is not NULL'); 293 notEqual(data.invalidReasons, null, 'invalidReasons is not NULL');
281 equal(data.invalidReasons.length, 0, 'data has 0 invalid reasons'); 294 equal(data.invalidReasons.length, 0, 'Errors object should not be empty.');
282 equal(data.mediaSequence, 0, 'MEDIA SEQUENCE tags after the first should be ignored'); 295 equal(data.mediaSequence, 0, 'MEDIA SEQUENCE tags after the first should be ignored');
283 }); 296 });
284 297
...@@ -291,7 +304,7 @@ ...@@ -291,7 +304,7 @@
291 304
292 notEqual(data, null, 'data is not NULL'); 305 notEqual(data, null, 'data is not NULL');
293 notEqual(data.invalidReasons, null, 'invalidReasons is not NULL'); 306 notEqual(data.invalidReasons, null, 'invalidReasons is not NULL');
294 equal(data.invalidReasons.length, 0, 'data has 0 invalid reasons'); 307 equal(data.invalidReasons.length, 0, 'Errors object should not be empty.');
295 equal(data.mediaSequence, 0, 'MEDIA SEQUENCE should default to 0 when not present.'); 308 equal(data.mediaSequence, 0, 'MEDIA SEQUENCE should default to 0 when not present.');
296 }); 309 });
297 310
...@@ -318,7 +331,7 @@ ...@@ -318,7 +331,7 @@
318 notEqual(data, null, 'data is not NULL'); 331 notEqual(data, null, 'data is not NULL');
319 notEqual(data.invalidReasons, null, 'invalidReasons is not NULL'); 332 notEqual(data.invalidReasons, null, 'invalidReasons is not NULL');
320 equal(data.invalidReasons.length, 1, 'data has 1 invalid reasons'); 333 equal(data.invalidReasons.length, 1, 'data has 1 invalid reasons');
321 equal(data.invalidReasons[0], 'Invalid Media Sequence Value: 1'); 334 equal(data.invalidReasons[0], 'Invalid Media Sequence Value: \'1\'');
322 }); 335 });
323 336
324 test('media sequence (-1) in the playlist', function() { 337 test('media sequence (-1) in the playlist', function() {
...@@ -331,7 +344,7 @@ ...@@ -331,7 +344,7 @@
331 notEqual(data, null, 'data is not NULL'); 344 notEqual(data, null, 'data is not NULL');
332 notEqual(data.invalidReasons, null, 'invalidReasons is not NULL'); 345 notEqual(data.invalidReasons, null, 'invalidReasons is not NULL');
333 equal(data.invalidReasons.length, 1, 'data has 1 invalid reasons'); 346 equal(data.invalidReasons.length, 1, 'data has 1 invalid reasons');
334 equal(data.invalidReasons[0], 'Invalid Media Sequence Value: -1'); 347 equal(data.invalidReasons[0], 'Invalid Media Sequence Value: \'-1\'');
335 }); 348 });
336 349
337 test('media sequence invalid (string) in the playlist', function() { 350 test('media sequence invalid (string) in the playlist', function() {
...@@ -344,7 +357,7 @@ ...@@ -344,7 +357,7 @@
344 notEqual(data, null, 'data is not NULL'); 357 notEqual(data, null, 'data is not NULL');
345 notEqual(data.invalidReasons, null, 'invalidReasons is not NULL'); 358 notEqual(data.invalidReasons, null, 'invalidReasons is not NULL');
346 equal(data.invalidReasons.length, 1, 'data has 1 invalid reasons'); 359 equal(data.invalidReasons.length, 1, 'data has 1 invalid reasons');
347 equal(data.invalidReasons[0], 'Invalid Media Sequence Value: asdfkasdkfl'); 360 equal(data.invalidReasons[0], 'Invalid Media Sequence Value: \'asdfkasdkfl\'');
348 }); 361 });
349 362
350 module('brightcove playlist', { 363 module('brightcove playlist', {
...@@ -365,4 +378,245 @@ ...@@ -365,4 +378,245 @@
365 equal(data.playlistItems[0].resolution.height, 224, 'First rendition index resolution height is correct'); 378 equal(data.playlistItems[0].resolution.height, 224, 'First rendition index resolution height is correct');
366 379
367 }); 380 });
381
382 /*3.3.2. EXTINF
383
384 The EXTINF tag specifies the duration of a media segment. It applies
385 only to the media segment that follows it, and MUST be followed by a
386 media segment URI. Each media segment MUST be preceded by an EXTINF
387 tag. Its format is:
388
389 #EXTINF:<duration>,<title>
390
391 where duration is an decimal-integer or decimal-floating-point number
392 that specifies the duration of the media segment in seconds.
393 Durations that are reported as integers SHOULD be rounded to the
394 nearest integer. Durations MUST be integers if the protocol version
395 of the Playlist file is less than 3. Durations SHOULD be floating-
396 point if the version is equal to or greater than 3. The remainder of
397 the line following the comma is an optional human-readable
398 informative title of the media segment.
399
400 The EXTINF duration of each media segment in the Playlist
401 file, when rounded to the nearest integer, MUST be less than or equal
402 to the target duration.
403 */
404
405 test('test valid extinf values in playlist', function() {
406 var
407 playlistTemplate = Handlebars.compile(window.playlist_extinf_template),
408 testData = {version: 4, extInf: '10', extInf1: '10', extInf2: '10', segment: 'hls_450k_video.ts'},
409 playlistData = playlistTemplate(testData),
410 data = m3u8parser.parse(playlistData);
411
412 notEqual(data, null, 'data is not NULL');
413 notEqual(data.invalidReasons, null, 'invalidReasons is not NULL');
414 equal(data.invalidReasons.length, 0, 'Errors object should not be empty.');
415 });
416
417 test('test valid extinf without associated segment in playlist', function() {
418 var
419 playlistTemplate = Handlebars.compile(window.playlist_extinf_template),
420 testData = {version: 4, extInf: '10', extInf1: '10', extInf2: '10'},
421 playlistData = playlistTemplate(testData),
422 data = m3u8parser.parse(playlistData);
423
424 notEqual(data, null, 'data is not NULL');
425 notEqual(data.invalidReasons, null, 'invalidReasons is not NULL');
426 equal(data.invalidReasons.length, 1, 'data has 1 invalid reasons');
427 //equal(data.invalidReasons[0], 'Invalid Segment Data: \'#EXTINF missing segment\'');
428 });
429
430 //
431 test('test invalid extinf values in playlist', function() {
432 var
433 playlistTemplate = Handlebars.compile(window.playlist_extinf_template),
434 testData = {version: 4, extInf: 'asdf', extInf1: '10', extInf2: '10', segment: 'hls_450k_video.ts'},
435 playlistData = playlistTemplate(testData),
436 data = m3u8parser.parse(playlistData);
437
438 notEqual(data, null, 'data is not NULL');
439 notEqual(data.invalidReasons, null, 'invalidReasons is not NULL');
440 equal(data.invalidReasons.length, 1, 'data has 1 invalid reasons');
441 });
442
443 //its best practice that every extinf have the same value, but its not required
444 test('test inconsistent extinf values in playlist below target duration', function() {
445 var
446 playlistTemplate = Handlebars.compile(window.playlist_extinf_template),
447 testData = {version: 4, extInf: '10', extInf1: '7', extInf2: '10', segment: 'hls_450k_video.ts'},
448 playlistData = playlistTemplate(testData),
449 data = m3u8parser.parse(playlistData);
450
451 notEqual(data, null, 'data is not NULL');
452 notEqual(data.invalidReasons, null, 'invalidReasons is not NULL');
453 equal(data.invalidReasons.length, 0, 'Errors object should not be empty.');
454 });
455
456 //extinf values must be below the target duration
457 test('test inconsistent extinf values in playlist above target duration', function() {
458 var
459 playlistTemplate = Handlebars.compile(window.playlist_extinf_template),
460 testData = {version: 4, extInf: '10', extInf1: '7', extInf2: '10', segment: 'hls_450k_video.ts'},
461 playlistData = playlistTemplate(testData),
462 data = m3u8parser.parse(playlistData);
463
464 notEqual(data, null, 'data is not NULL');
465 notEqual(data.invalidReasons, null, 'invalidReasons is not NULL');
466 equal(data.invalidReasons.length, 1, 'data has 1 invalid reasons');
467 equal(data.invalidReasons[0], 'Invalid Segment Data: \'#EXTINF value higher than #TARGETDURATION\'');
468 });
469
470 //extinf values must be below the target duration
471 test('test floating-point values not accepted with version 3', function() {
472 var
473 playlistTemplate = Handlebars.compile(window.playlist_extinf_template),
474 testData = {version: 3, extInf: '10.5', extInf1: '10.5', extInf2: '10.5', segment: 'hls_450k_video.ts'},
475 playlistData = playlistTemplate(testData),
476 data = m3u8parser.parse(playlistData);
477
478 notEqual(data, null, 'data is not NULL');
479 notEqual(data.invalidReasons, null, 'invalidReasons is not NULL');
480 equal(data.invalidReasons.length, 1, 'data has 1 invalid reasons');
481 equal(data.invalidReasons[0], 'Invalid Segment Data: \'#EXTINF value not an integer\'');
482 });
483
484 //extinf values must be below the target duration
485 test('test floating-point values accepted with version 4', function() {
486 var
487 playlistTemplate = Handlebars.compile(window.playlist_extinf_template),
488 testData = {version: 4, extInf: '10.5', extInf1: '10.5', extInf2: '10.5', segment: 'hls_450k_video.ts'},
489 playlistData = playlistTemplate(testData),
490 data = m3u8parser.parse(playlistData);
491
492 notEqual(data, null, 'data is not NULL');
493 notEqual(data.invalidReasons, null, 'invalidReasons is not NULL');
494 equal(data.invalidReasons.length, 0, 'Errors object should not be empty.');
495 });
496
497 //extinf values must be below the target duration
498 test('test empty EXTINF values', function() {
499 var
500 playlistTemplate = Handlebars.compile(window.playlist_extinf_template),
501 testData = {version: 4, extInf: '', extInf1: '10.5', extInf2: '10.5', segment: 'hls_450k_video.ts'},
502 playlistData = playlistTemplate(testData),
503 data = m3u8parser.parse(playlistData);
504
505 notEqual(data, null, 'data is not NULL');
506 notEqual(data.invalidReasons, null, 'invalidReasons is not NULL');
507 equal(data.invalidReasons.length, 1, 'data has 1 invalid reasons');
508 equal(data.invalidReasons[0], 'Invalid Segment Data: \'#EXTINF value empty\'');
509 });
510
511 /*
512 3.3.6. EXT-X-ALLOW-CACHE
513
514 The EXT-X-ALLOW-CACHE tag indicates whether the client MAY or MUST
515 NOT cache downloaded media segments for later replay. It MAY occur
516 anywhere in the Playlist file; it MUST NOT occur more than once. The
517 EXT-X-ALLOW-CACHE tag applies to all segments in the playlist. Its
518 format is:
519
520 #EXT-X-ALLOW-CACHE:<YES|NO>
521 */
522
523 test('test EXT-X-ALLOW-CACHE YES', function() {
524 var
525 playlistTemplate = Handlebars.compile(window.playlist_allow_cache),
526 testData = {version: 4, allowCache: 'YES'},
527 playlistData = playlistTemplate(testData),
528 data = m3u8parser.parse(playlistData);
529
530 notEqual(data, null, 'data is not NULL');
531 notEqual(data.invalidReasons, null, 'invalidReasons is not NULL');
532 equal(data.invalidReasons.length, 0, 'Errors object should not be empty.');
533 equal(data.allowCache, 'YES', 'EXT-X-ALLOW-CACHE should be YES');
534 });
535
536 test('test EXT-X-ALLOW-CACHE NO', function() {
537 var
538 playlistTemplate = Handlebars.compile(window.playlist_allow_cache),
539 testData = {version: 4, allowCache: 'NO'},
540 playlistData = playlistTemplate(testData),
541 data = m3u8parser.parse(playlistData);
542
543 notEqual(data, null, 'data is not NULL');
544 notEqual(data.invalidReasons, null, 'invalidReasons is not NULL');
545 equal(data.invalidReasons.length, 0, 'Errors object should not be empty.');
546 equal(data.allowCache, 'NO', 'EXT-X-ALLOW-CACHE should be NO');
547 });
548
549 test('test EXT-X-ALLOW-CACHE invalid, default to YES', function() {
550 var
551 playlistTemplate = Handlebars.compile(window.playlist_allow_cache),
552 testData = {version: 4, allowCache: 'YESTERDAYNO'},
553 playlistData = playlistTemplate(testData),
554 data = m3u8parser.parse(playlistData);
555
556 notEqual(data, null, 'data is not NULL');
557 notEqual(data.invalidReasons, null, 'invalidReasons is not NULL');
558 equal(data.invalidReasons.length, 1, 'data has 1 invalid reasons');
559 equal(data.invalidReasons[0], 'Invalid EXT-X-ALLOW-CACHE value: \'YESTERDAYNO\'');
560 equal(data.allowCache, 'YES', 'EXT-X-ALLOW-CACHE should default to YES.');
561 });
562
563 test('test EXT-X-ALLOW-CACHE empty, default to YES', function() {
564 var
565 playlistTemplate = Handlebars.compile(window.playlist_allow_cache),
566 testData = {version: 4, allowCache: ''},
567 playlistData = playlistTemplate(testData),
568 data = m3u8parser.parse(playlistData);
569
570 notEqual(data, null, 'data is not NULL');
571 notEqual(data.invalidReasons, null, 'invalidReasons is not NULL');
572 equal(data.invalidReasons.length, 1, 'data has 1 invalid reasons');
573 equal(data.invalidReasons[0], 'Invalid EXT-X-ALLOW-CACHE value: \'\'');
574 equal(data.allowCache, 'YES', 'EXT-X-ALLOW-CACHE should default to YES.');
575 });
576
577 test('test EXT-X-ALLOW-CACHE missing, default to YES', function() {
578 var
579 playlistTemplate = Handlebars.compile(window.playlist_allow_cache),
580 testData = {version: 4},
581 playlistData = playlistTemplate(testData),
582 data = m3u8parser.parse(playlistData);
583
584 notEqual(data, null, 'data is not NULL');
585 notEqual(data.invalidReasons, null, 'invalidReasons is not NULL');
586 equal(data.invalidReasons.length, 1, 'No EXT-X-ALLOW-CACHE specified. Default: YES.');
587 equal(data.allowCache, 'YES', 'EXT-X-ALLOW-CACHE should default to YES');
588 });
589
590 test('test EXT-X-BYTERANGE valid', function() {
591 var
592 playlistTemplate = Handlebars.compile(window.playlist_byte_range),
593 testData = {version: 4, byteRange: '522828,0', byteRange1: '587500,522828', byteRange2: '44556,8353216'},
594 playlistData = playlistTemplate(testData),
595 data = m3u8parser.parse(playlistData);
596
597 notEqual(data, null, 'data is not NULL');
598 notEqual(data.invalidReasons, null, 'invalidReasons is not NULL');
599 equal(data.invalidReasons.length, 0, 'Errors object should be empty.');
600 //TODO: Validate the byteRange info
601 equal(data.mediaItems.length, 16, '16 segments should have been parsed.');
602 equal(data.mediaItems[0].byterange, testData.byteRange, 'byteRange incorrect.');
603 equal(data.mediaItems[1].byterange, testData.byteRange1, 'byteRange1 incorrect.');
604 equal(data.mediaItems[15].byterange, testData.byteRange2, 'byteRange2 incorrect.');
605 });
606
607 test('test EXT-X-BYTERANGE used but version is < 4', function() {
608 var
609 playlistTemplate = Handlebars.compile(window.playlist_byte_range),
610 testData = {version: 3, byteRange: ['522828,0'], byteRange1: ['587500,522828'], byteRange2: ['44556,8353216']},
611 playlistData = playlistTemplate(testData),
612 data = m3u8parser.parse(playlistData);
613
614 notEqual(data, null, 'data is not NULL');
615 equal(data.mediaItems.length, 16, '16 segments should have been parsed.');
616 notEqual(data.invalidReasons, null, 'there should be an error');
617 equal(data.invalidReasons.length, 1, 'there should be 1 error');
618 //TODO: Validate the byteRange info
619 equal(data.invalidReasons[0], 'EXT-X-BYTERANGE used but version is < 4.')
620 });
621
368 })(this); 622 })(this);
...\ No newline at end of file ...\ No newline at end of file
......
1 window.playlist_allow_cache = '#EXTM3U\n'+
2 '#EXT-X-TARGETDURATION:10\n' +
3 '#EXT-X-VERSION:{{{version}}}\n' +
4 '{{#if allowCache}}#EXT-X-ALLOW-CACHE:{{{allowCache}}}{{/if}}\n' +
5 '#EXT-X-MEDIA-SEQUENCE:0\n' +
6 '#EXT-X-PLAYLIST-TYPE:VOD\n' +
7 '#EXTINF:10,\n' +
8 '#EXT-X-BYTERANGE:522828@0\n' +
9 'hls_450k_video.ts\n' +
10 '#EXTINF:10,\n' +
11 '#EXT-X-BYTERANGE:587500@522828\n' +
12 'hls_450k_video.ts\n' +
13 '#EXTINF:10,\n' +
14 '#EXT-X-BYTERANGE:713084@1110328\n' +
15 'hls_450k_video.ts\n' +
16 '#EXTINF:10,\n' +
17 '#EXT-X-BYTERANGE:476580@1823412\n' +
18 'hls_450k_video.ts\n' +
19 '#EXTINF:10,\n' +
20 '#EXT-X-BYTERANGE:535612@2299992\n' +
21 'hls_450k_video.ts\n' +
22 '#EXTINF:10,\n' +
23 '#EXT-X-BYTERANGE:207176@2835604\n' +
24 'hls_450k_video.ts\n' +
25 '#EXTINF:10,\n' +
26 '#EXT-X-BYTERANGE:455900@3042780\n' +
27 'hls_450k_video.ts\n' +
28 '#EXTINF:10,\n' +
29 '#EXT-X-BYTERANGE:657248@3498680\n' +
30 'hls_450k_video.ts\n' +
31 '#EXTINF:10,\n' +
32 '#EXT-X-BYTERANGE:571708@4155928\n' +
33 'hls_450k_video.ts\n' +
34 '#EXTINF:10,\n' +
35 '#EXT-X-BYTERANGE:485040@4727636\n' +
36 'hls_450k_video.ts\n' +
37 '#EXTINF:10,\n' +
38 '#EXT-X-BYTERANGE:709136@5212676\n' +
39 'hls_450k_video.ts\n' +
40 '#EXTINF:10,\n' +
41 '#EXT-X-BYTERANGE:730004@5921812\n' +
42 'hls_450k_video.ts\n' +
43 '#EXTINF:10,\n' +
44 '#EXT-X-BYTERANGE:456276@6651816\n' +
45 'hls_450k_video.ts\n' +
46 '#EXTINF:10,\n' +
47 '#EXT-X-BYTERANGE:468684@7108092\n' +
48 'hls_450k_video.ts' +
49 '#EXTINF:10,\n' +
50 '#EXT-X-BYTERANGE:444996@7576776\n' +
51 'hls_450k_video.ts\n' +
52 '#EXTINF:10,\n' +
53 '#EXT-X-BYTERANGE:331444@8021772\n' +
54 'hls_450k_video.ts\n' +
55 '#EXTINF:1.4167,\n' +
56 '#EXT-X-BYTERANGE:44556@8353216\n' +
57 'hls_450k_video.ts\n' +
58 '#EXT-X-ENDLIST';
1 window.playlist_byte_range = '#EXTM3U\n'+
2 '#EXT-X-TARGETDURATION:10\n' +
3 '#EXT-X-VERSION:{{{version}}}\n' +
4 '#EXT-X-MEDIA-SEQUENCE:0\n' +
5 '#EXT-X-PLAYLIST-TYPE:VOD\n' +
6 '#EXTINF:10,\n' +
7 '{{#if byteRange}}#EXT-X-BYTERANGE:{{{byteRange}}}{{/if}}\n' +
8 //'#EXT-X-BYTERANGE:522828@0\n' +
9 'hls_450k_video.ts\n' +
10 '#EXTINF:10,\n' +
11 '{{#if byteRange1}}#EXT-X-BYTERANGE:{{{byteRange1}}}{{/if}}\n' +
12 //'#EXT-X-BYTERANGE:587500@522828\n' +
13 'hls_450k_video.ts\n' +
14 '#EXTINF:10,\n' +
15 '#EXT-X-BYTERANGE:713084@1110328\n' +
16 'hls_450k_video.ts\n' +
17 '#EXTINF:10,\n' +
18 '#EXT-X-BYTERANGE:476580@1823412\n' +
19 'hls_450k_video.ts\n' +
20 '#EXTINF:10,\n' +
21 '#EXT-X-BYTERANGE:535612@2299992\n' +
22 'hls_450k_video.ts\n' +
23 '#EXTINF:10,\n' +
24 '#EXT-X-BYTERANGE:207176@2835604\n' +
25 'hls_450k_video.ts\n' +
26 '#EXTINF:10,\n' +
27 '#EXT-X-BYTERANGE:455900@3042780\n' +
28 'hls_450k_video.ts\n' +
29 '#EXTINF:10,\n' +
30 '#EXT-X-BYTERANGE:657248@3498680\n' +
31 'hls_450k_video.ts\n' +
32 '#EXTINF:10,\n' +
33 '#EXT-X-BYTERANGE:571708@4155928\n' +
34 'hls_450k_video.ts\n' +
35 '#EXTINF:10,\n' +
36 '#EXT-X-BYTERANGE:485040@4727636\n' +
37 'hls_450k_video.ts\n' +
38 '#EXTINF:10,\n' +
39 '#EXT-X-BYTERANGE:709136@5212676\n' +
40 'hls_450k_video.ts\n' +
41 '#EXTINF:10,\n' +
42 '#EXT-X-BYTERANGE:730004@5921812\n' +
43 'hls_450k_video.ts\n' +
44 '#EXTINF:10,\n' +
45 '#EXT-X-BYTERANGE:456276@6651816\n' +
46 'hls_450k_video.ts\n' +
47 '#EXTINF:10,\n' +
48 '#EXT-X-BYTERANGE:468684@7108092\n' +
49 'hls_450k_video.ts' +
50 '#EXTINF:10,\n' +
51 '#EXT-X-BYTERANGE:444996@7576776\n' +
52 'hls_450k_video.ts\n' +
53 '#EXTINF:10,\n' +
54 '#EXT-X-BYTERANGE:331444@8021772\n' +
55 'hls_450k_video.ts\n' +
56 '#EXTINF:1.4167,\n' +
57 '{{#if byteRange2}}#EXT-X-BYTERANGE:{{{byteRange2}}}{{/if}}\n' +
58 //'#EXT-X-BYTERANGE:44556@8353216\n' +
59 'hls_450k_video.ts\n' +
60 '#EXT-X-ENDLIST';
1 window.playlist_extinf_template = '#EXTM3U\n'+
2 '#EXT-X-TARGETDURATION:10\n' +
3 '#EXT-X-VERSION:{{{version}}}\n' +
4 '#EXT-X-MEDIA-SEQUENCE:0\n' +
5 '#EXT-X-PLAYLIST-TYPE:VOD\n' +
6 '{{#if extInf}}#EXTINF:{{{extInf}}}{{/if}}\n' +
7 '#EXT-X-BYTERANGE:522828@0\n' +
8 '{{#if segment}}{{{segment}}}\n{{/if}}' +
9 '{{#if extInf1}}#EXTINF:{{{extInf1}}}{{/if}}\n' +
10 '#EXT-X-BYTERANGE:587500@522828\n' +
11 'hls_450k_video.ts\n' +
12 '#EXTINF:10,\n' +
13 '#EXT-X-BYTERANGE:713084@1110328\n' +
14 'hls_450k_video.ts\n' +
15 '#EXTINF:10,\n' +
16 '#EXT-X-BYTERANGE:476580@1823412\n' +
17 'hls_450k_video.ts\n' +
18 '#EXTINF:10,\n' +
19 '#EXT-X-BYTERANGE:535612@2299992\n' +
20 'hls_450k_video.ts\n' +
21 '#EXTINF:10,\n' +
22 '#EXT-X-BYTERANGE:207176@2835604\n' +
23 'hls_450k_video.ts\n' +
24 '#EXTINF:10,\n' +
25 '#EXT-X-BYTERANGE:455900@3042780\n' +
26 'hls_450k_video.ts\n' +
27 '#EXTINF:10,\n' +
28 '#EXT-X-BYTERANGE:657248@3498680\n' +
29 'hls_450k_video.ts\n' +
30 '#EXTINF:10,\n' +
31 '#EXT-X-BYTERANGE:571708@4155928\n' +
32 'hls_450k_video.ts\n' +
33 '#EXTINF:10,\n' +
34 '#EXT-X-BYTERANGE:485040@4727636\n' +
35 'hls_450k_video.ts\n' +
36 '#EXTINF:10,\n' +
37 '#EXT-X-BYTERANGE:709136@5212676\n' +
38 'hls_450k_video.ts\n' +
39 '#EXTINF:10,\n' +
40 '#EXT-X-BYTERANGE:730004@5921812\n' +
41 'hls_450k_video.ts\n' +
42 '#EXTINF:10,\n' +
43 '#EXT-X-BYTERANGE:456276@6651816\n' +
44 'hls_450k_video.ts\n' +
45 '#EXTINF:10,\n' +
46 '#EXT-X-BYTERANGE:468684@7108092\n' +
47 'hls_450k_video.ts' +
48 '#EXTINF:10,\n' +
49 '#EXT-X-BYTERANGE:444996@7576776\n' +
50 'hls_450k_video.ts\n' +
51 '#EXTINF:10,\n' +
52 '#EXT-X-BYTERANGE:331444@8021772\n' +
53 'hls_450k_video.ts\n' +
54 '{{#if extInf2}}#EXTINF:{{{extInf2}}}{{/if}}\n' +
55 '#EXT-X-BYTERANGE:44556@8353216\n' +
56 'hls_450k_video.ts\n' +
57 '#EXT-X-ENDLIST';
1 window.playlist_media_sequence_template = '#EXTM3U\n'+ 1 window.playlist_media_sequence_template = '#EXTM3U\n'+
2 '#EXT-X-PLAYLIST-TYPE:VOD\n'+ 2 '#EXT-X-PLAYLIST-TYPE:VOD\n'+
3 '{{#if mediaSequence}}#EXT-X-MEDIA-SEQUENCE:{{{mediaSequence}}}{{/if}}\n'+ 3 '{{#if mediaSequence}}#EXT-X-MEDIA-SEQUENCE:{{{mediaSequence}}}{{/if}}\n'+
4 '{{#if mediaSequence2}}#EXT-X-MEDIA-SEQUENCE:{{{mediaSequence2}}}{{/if}}\n'+ 4 '{{#if mediaSequence1}}#EXT-X-MEDIA-SEQUENCE:{{{mediaSequence2}}}{{/if}}\n'+
5 '#EXT-X-ALLOW-CACHE:YES\n'+ 5 '#EXT-X-ALLOW-CACHE:YES\n'+
6 '#EXT-X-TARGETDURATION:8\n'+ 6 '#EXT-X-TARGETDURATION:8\n'+
7 '#EXTINF:6.640,{}\n'+ 7 '#EXTINF:6.640,{}\n'+
......
...@@ -32,6 +32,10 @@ ...@@ -32,6 +32,10 @@
32 <script src="manifest/playlist_type_template.js"></script> 32 <script src="manifest/playlist_type_template.js"></script>
33 <script src="manifest/playlist_media_sequence_template.js"></script> 33 <script src="manifest/playlist_media_sequence_template.js"></script>
34 <script src="manifest/playlist_target_duration_template.js"></script> 34 <script src="manifest/playlist_target_duration_template.js"></script>
35 <script src="manifest/playlist_extinf_template.js"></script>
36 <script src="manifest/playlist_allow_cache_template.js"></script>
37 <script src="manifest/playlist_byte_range_template.js"></script>
38
35 <!-- M3U8 --> 39 <!-- M3U8 -->
36 <!-- SEGMENT --> 40 <!-- SEGMENT -->
37 <script src="tsSegment-bc.js"></script> 41 <script src="tsSegment-bc.js"></script>
......