Pull out XHR helper
Create a helper method for creating XMLHttpRequests and migrate downloadPlaylist to using it.
Showing
1 changed file
with
119 additions
and
98 deletions
... | @@ -94,6 +94,35 @@ var | ... | @@ -94,6 +94,35 @@ var |
94 | } | 94 | } |
95 | }, | 95 | }, |
96 | 96 | ||
97 | xhr = function(url, callback) { | ||
98 | var | ||
99 | options = { | ||
100 | method: 'GET' | ||
101 | }, | ||
102 | request; | ||
103 | if (typeof url === 'object') { | ||
104 | options = videojs.util.mergeOptions(options, url); | ||
105 | url = options.url; | ||
106 | } | ||
107 | request = new window.XMLHttpRequest(); | ||
108 | request.open(options.method, url); | ||
109 | request.onreadystatechange = function() { | ||
110 | // wait until the request completes | ||
111 | if (this.readyState !== 4) { | ||
112 | return; | ||
113 | } | ||
114 | |||
115 | // request error | ||
116 | if (this.status >= 400 || this.status === 0) { | ||
117 | return callback.call(this, true, url); | ||
118 | } | ||
119 | |||
120 | return callback.call(this, false, url); | ||
121 | }; | ||
122 | request.send(null); | ||
123 | return request; | ||
124 | }, | ||
125 | |||
97 | /** | 126 | /** |
98 | * TODO - Document this great feature. | 127 | * TODO - Document this great feature. |
99 | * | 128 | * |
... | @@ -350,7 +379,7 @@ var | ... | @@ -350,7 +379,7 @@ var |
350 | if (!playlist.segments || | 379 | if (!playlist.segments || |
351 | mediaSequence < (playlist.mediaSequence || 0) || | 380 | mediaSequence < (playlist.mediaSequence || 0) || |
352 | mediaSequence > (playlist.mediaSequence || 0) + playlist.segments.length) { | 381 | mediaSequence > (playlist.mediaSequence || 0) + playlist.segments.length) { |
353 | downloadPlaylist(resolveUrl(srcUrl, playlist.uri)); | 382 | xhr(resolveUrl(srcUrl, playlist.uri), downloadPlaylist); |
354 | } else { | 383 | } else { |
355 | player.hls.mediaIndex = | 384 | player.hls.mediaIndex = |
356 | findCorrespondingMediaIndex(player.hls.mediaIndex, | 385 | findCorrespondingMediaIndex(player.hls.mediaIndex, |
... | @@ -437,120 +466,112 @@ var | ... | @@ -437,120 +466,112 @@ var |
437 | }; | 466 | }; |
438 | 467 | ||
439 | /** | 468 | /** |
440 | * Download an M3U8 and update the current manifest object. If the provided | 469 | * Callback that is invoked when a playlist finishes |
441 | * URL is a master playlist, the default variant will be downloaded and | 470 | * downloading. If the response is a master playlist, the default |
442 | * parsed as well. Triggers `loadedmanifest` once for each playlist that is | 471 | * variant will be downloaded and parsed as well. Triggers |
443 | * downloaded and `loadedmetadata` after at least one media playlist has | 472 | * `loadedmanifest` once for each playlist that is downloaded and |
444 | * been parsed. Whether multiple playlists were downloaded or not, when | 473 | * `loadedmetadata` after at least one media playlist has been |
445 | * `loadedmetadata` fires a parsed or inferred master playlist object will | 474 | * parsed. Whether multiple playlists were downloaded or not, when |
446 | * be available as `player.hls.master`. | 475 | * `loadedmetadata` fires a parsed or inferred master playlist |
476 | * object will be available as `player.hls.master`. | ||
447 | * | 477 | * |
478 | * @param error {*} truthy if the request was not successful | ||
448 | * @param url {string} a URL to the M3U8 file to process | 479 | * @param url {string} a URL to the M3U8 file to process |
449 | */ | 480 | */ |
450 | downloadPlaylist = function(url) { | 481 | downloadPlaylist = function(error, url) { |
451 | var xhr = new window.XMLHttpRequest(); | 482 | var i, parser, playlist, playlistUri, refreshDelay; |
452 | xhr.open('GET', url); | 483 | |
453 | xhr.onreadystatechange = function() { | 484 | if (error) { |
454 | var i, parser, playlist, playlistUri, refreshDelay; | 485 | player.hls.error = { |
486 | status: this.status, | ||
487 | message: 'HLS playlist request error at URL: ' + url, | ||
488 | code: (this.status >= 500) ? 4 : 2 | ||
489 | }; | ||
490 | player.trigger('error'); | ||
491 | return; | ||
492 | } | ||
455 | 493 | ||
456 | // wait until the request completes | 494 | // readystate DONE |
457 | if (xhr.readyState !== 4) { | 495 | parser = new videojs.m3u8.Parser(); |
458 | return; | 496 | parser.push(this.responseText); |
459 | } | ||
460 | 497 | ||
461 | if (xhr.status >= 400 || this.status === 0) { | 498 | // master playlists |
462 | player.hls.error = { | 499 | if (parser.manifest.playlists) { |
463 | status: xhr.status, | 500 | player.hls.master = parser.manifest; |
464 | message: 'HLS playlist request error at URL: ' + url, | 501 | xhr(resolveUrl(url, parser.manifest.playlists[0].uri), downloadPlaylist); |
465 | code: (xhr.status >= 500) ? 4 : 2 | 502 | player.trigger('loadedmanifest'); |
466 | }; | 503 | return; |
467 | player.trigger('error'); | 504 | } |
468 | return; | ||
469 | } | ||
470 | 505 | ||
471 | // readystate DONE | 506 | // media playlists |
472 | parser = new videojs.m3u8.Parser(); | 507 | refreshDelay = (parser.manifest.targetDuration || 10) * 1000; |
473 | parser.push(xhr.responseText); | 508 | if (player.hls.master) { |
509 | // merge this playlist into the master | ||
510 | i = player.hls.master.playlists.length; | ||
511 | |||
512 | while (i--) { | ||
513 | playlist = player.hls.master.playlists[i]; | ||
514 | playlistUri = resolveUrl(srcUrl, playlist.uri); | ||
515 | if (playlistUri === url) { | ||
516 | // if the playlist is unchanged since the last reload, | ||
517 | // try again after half the target duration | ||
518 | // http://tools.ietf.org/html/draft-pantos-http-live-streaming-12#section-6.3.4 | ||
519 | if (playlist.segments && | ||
520 | playlist.segments.length === parser.manifest.segments.length) { | ||
521 | refreshDelay /= 2; | ||
522 | } | ||
474 | 523 | ||
475 | // master playlists | 524 | player.hls.master.playlists[i] = |
476 | if (parser.manifest.playlists) { | 525 | videojs.util.mergeOptions(playlist, parser.manifest); |
477 | player.hls.master = parser.manifest; | ||
478 | downloadPlaylist(resolveUrl(url, parser.manifest.playlists[0].uri)); | ||
479 | player.trigger('loadedmanifest'); | ||
480 | return; | ||
481 | } | ||
482 | 526 | ||
483 | // media playlists | 527 | if (playlist !== player.hls.media) { |
484 | refreshDelay = (parser.manifest.targetDuration || 10) * 1000; | 528 | continue; |
485 | if (player.hls.master) { | ||
486 | // merge this playlist into the master | ||
487 | i = player.hls.master.playlists.length; | ||
488 | |||
489 | while (i--) { | ||
490 | playlist = player.hls.master.playlists[i]; | ||
491 | playlistUri = resolveUrl(srcUrl, playlist.uri); | ||
492 | if (playlistUri === url) { | ||
493 | // if the playlist is unchanged since the last reload, | ||
494 | // try again after half the target duration | ||
495 | // http://tools.ietf.org/html/draft-pantos-http-live-streaming-12#section-6.3.4 | ||
496 | if (playlist.segments && | ||
497 | playlist.segments.length === parser.manifest.segments.length) { | ||
498 | refreshDelay /= 2; | ||
499 | } | ||
500 | |||
501 | player.hls.master.playlists[i] = | ||
502 | videojs.util.mergeOptions(playlist, parser.manifest); | ||
503 | |||
504 | if (playlist !== player.hls.media) { | ||
505 | continue; | ||
506 | } | ||
507 | |||
508 | // determine the new mediaIndex if we're updating the | ||
509 | // current media playlist | ||
510 | player.hls.mediaIndex = | ||
511 | findCorrespondingMediaIndex(player.hls.mediaIndex, | ||
512 | playlist, | ||
513 | parser.manifest); | ||
514 | player.hls.media = parser.manifest; | ||
515 | } | 529 | } |
530 | |||
531 | // determine the new mediaIndex if we're updating the | ||
532 | // current media playlist | ||
533 | player.hls.mediaIndex = | ||
534 | findCorrespondingMediaIndex(player.hls.mediaIndex, | ||
535 | playlist, | ||
536 | parser.manifest); | ||
537 | player.hls.media = parser.manifest; | ||
516 | } | 538 | } |
517 | } else { | ||
518 | // infer a master playlist if none was previously requested | ||
519 | player.hls.master = { | ||
520 | playlists: [parser.manifest] | ||
521 | }; | ||
522 | parser.manifest.uri = url; | ||
523 | } | 539 | } |
540 | } else { | ||
541 | // infer a master playlist if none was previously requested | ||
542 | player.hls.master = { | ||
543 | playlists: [parser.manifest] | ||
544 | }; | ||
545 | parser.manifest.uri = url; | ||
546 | } | ||
524 | 547 | ||
525 | // check the playlist for updates if EXT-X-ENDLIST isn't present | 548 | // check the playlist for updates if EXT-X-ENDLIST isn't present |
526 | if (!parser.manifest.endList) { | 549 | if (!parser.manifest.endList) { |
527 | window.setTimeout(function() { | 550 | window.setTimeout(function() { |
528 | downloadPlaylist(url); | 551 | xhr(url, downloadPlaylist); |
529 | }, refreshDelay); | 552 | }, refreshDelay); |
530 | } | 553 | } |
531 | 554 | ||
532 | // always start playback with the default rendition | 555 | // always start playback with the default rendition |
533 | if (!player.hls.media) { | 556 | if (!player.hls.media) { |
534 | player.hls.media = player.hls.master.playlists[0]; | 557 | player.hls.media = player.hls.master.playlists[0]; |
535 | 558 | ||
536 | // update the duration | 559 | // update the duration |
537 | player.duration(totalDuration(parser.manifest)); | 560 | player.duration(totalDuration(parser.manifest)); |
538 | 561 | ||
539 | // periodicaly check if the buffer needs to be refilled | 562 | // periodicaly check if the buffer needs to be refilled |
540 | player.on('timeupdate', fillBuffer); | 563 | player.on('timeupdate', fillBuffer); |
541 | 564 | ||
542 | player.trigger('loadedmanifest'); | 565 | player.trigger('loadedmanifest'); |
543 | player.trigger('loadedmetadata'); | 566 | player.trigger('loadedmetadata'); |
544 | fillBuffer(); | 567 | fillBuffer(); |
545 | return; | 568 | return; |
546 | } | 569 | } |
547 | 570 | ||
548 | // select a playlist and download its metadata if necessary | 571 | // select a playlist and download its metadata if necessary |
549 | updateCurrentPlaylist(); | 572 | updateCurrentPlaylist(); |
550 | 573 | ||
551 | player.trigger('loadedmanifest'); | 574 | player.trigger('loadedmanifest'); |
552 | }; | ||
553 | xhr.send(null); | ||
554 | }; | 575 | }; |
555 | 576 | ||
556 | /** | 577 | /** |
... | @@ -668,7 +689,7 @@ var | ... | @@ -668,7 +689,7 @@ var |
668 | sourceBuffer.appendBuffer(segmentParser.getFlvHeader()); | 689 | sourceBuffer.appendBuffer(segmentParser.getFlvHeader()); |
669 | 690 | ||
670 | player.hls.mediaIndex = 0; | 691 | player.hls.mediaIndex = 0; |
671 | downloadPlaylist(srcUrl); | 692 | xhr(srcUrl, downloadPlaylist); |
672 | }); | 693 | }); |
673 | player.src([{ | 694 | player.src([{ |
674 | src: videojs.URL.createObjectURL(mediaSource), | 695 | src: videojs.URL.createObjectURL(mediaSource), | ... | ... |
-
Please register or sign in to post a comment